Index: dll/win32/apphelp/CMakeLists.txt =================================================================== --- dll/win32/apphelp/CMakeLists.txt (revision 0) +++ dll/win32/apphelp/CMakeLists.txt (working copy) @@ -0,0 +1,20 @@ + +spec2def(apphelp.dll apphelp.spec) + +list(APPEND SOURCE + apphelp.c + sdbapi.c + layer.c + apphelp.spec + apphelp.h + ${CMAKE_CURRENT_BINARY_DIR}/apphelp_stubs.c) + +add_library(apphelp SHARED + ${SOURCE} + ${CMAKE_CURRENT_BINARY_DIR}/apphelp.def) + +set_module_type(apphelp win32dll) +target_link_libraries(apphelp wine) +#add_delay_importlibs(apphelp version imagehlp user32) +add_importlibs(apphelp msvcrt kernel32 ntdll) +add_cd_file(TARGET apphelp DESTINATION reactos/system32 FOR all) Index: dll/win32/apphelp/apphelp.c =================================================================== --- dll/win32/apphelp/apphelp.c (revision 0) +++ dll/win32/apphelp/apphelp.c (working copy) @@ -0,0 +1,132 @@ +/* + * Copyright 2011 André Hentschel + * Copyright 2013 Mislav Blaževic + * 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 + */ + +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winver.h" +#include "strsafe.h" +#include "apphelp.h" + +#include "wine/winternl.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +/* from dpfilter.h */ +#define DPFLTR_APPCOMPAT_ID 123 + +#define STATUS_SUCCESS ((NTSTATUS)0) + +ULONG g_ShimDebugLevel = 0xffffffff; + +void ApphelppInitDebugLevel() +{ + UNICODE_STRING DebugKey, DebugValue; + HRESULT hr; + ULONG NewLevel = 0; + + RtlInitUnicodeString(&DebugKey, L"SHIM_DEBUG_LEVEL"); + DebugValue.MaximumLength = 40 * sizeof(WCHAR); + DebugValue.Buffer = SdbAlloc(DebugValue.MaximumLength); + DebugValue.Length = 0; + + /* Hold the lock as short as possible. */ + RtlAcquirePebLock(); + hr = RtlQueryEnvironmentVariable_U(NULL, &DebugKey, &DebugValue); + RtlReleasePebLock(); + + if (SUCCEEDED(hr)) + { + if (FAILED(RtlUnicodeStringToInteger(&DebugValue, 10, &NewLevel))) + NewLevel = 0; + } + g_ShimDebugLevel = NewLevel; +} + +BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) +{ + switch (reason) + { +#ifndef __REACTOS__ + case DLL_WINE_PREATTACH: + return FALSE; /* prefer native version */ +#endif + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( hinst ); + SdbpHeapInit(); + break; + case DLL_PROCESS_DETACH: + SdbpHeapDeinit(); + break; + } + return TRUE; +} + + +/** + * Outputs diagnostic info. + * + * @param [in] Level The level to log this message with, choose any of [SHIM_ERR, + * SHIM_WARN, SHIM_INFO]. + * @param [in] FunctionName The function this log should be attributed to. + * @param [in] Format The format string. + * @param ... Variable arguments providing additional information. + * + * @return Success: TRUE Failure: FALSE. + */ +BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...) +{ + char Buffer[512]; + va_list ArgList; + char* Current = Buffer, *LevelStr; + size_t Length = sizeof(Buffer); + + if (g_ShimDebugLevel == 0xffffffff) + ApphelppInitDebugLevel(); + + if (Level > g_ShimDebugLevel) + return FALSE; + + switch(Level) + { + case SHIM_ERR: + LevelStr = "Err "; + Level = DPFLTR_MASK | (1 << DPFLTR_ERROR_LEVEL); + break; + case SHIM_WARN: + LevelStr = "Warn"; + Level = DPFLTR_MASK | (1 << DPFLTR_WARNING_LEVEL); + break; + case SHIM_INFO: + LevelStr = "Info"; + Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL); + break; + default: + LevelStr = "User"; + Level = DPFLTR_MASK | (1 << DPFLTR_INFO_LEVEL); + break; + } + StringCchPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, "[%s][%-20s] ", LevelStr, FunctionName); + va_start(ArgList, Format); + StringCchVPrintfExA(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList); + va_end(ArgList); + return SUCCEEDED(DbgPrintEx(DPFLTR_APPCOMPAT_ID, Level, "%s", Buffer)); +} + Index: dll/win32/apphelp/apphelp.h =================================================================== --- dll/win32/apphelp/apphelp.h (revision 0) +++ dll/win32/apphelp/apphelp.h (working copy) @@ -0,0 +1,59 @@ +/* + * Copyright 2013 Mislav Blaževic + * 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 + */ + + +typedef enum _SHIM_LOG_LEVEL { + SHIM_ERR = 1, + SHIM_WARN = 2, + SHIM_INFO = 3, +}SHIM_LOG_LEVEL; + +/* apphelp.c */ +BOOL WINAPIV ShimDbgPrint(SHIM_LOG_LEVEL Level, PCSTR FunctionName, PCSTR Format, ...); +extern ULONG g_ShimDebugLevel; + +#define SHIM_ERR(fmt, ...) do { if(g_ShimDebugLevel) ShimDbgPrint(SHIM_ERR, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while(0) +#define SHIM_WARN(fmt, ...) do { if(g_ShimDebugLevel) ShimDbgPrint(SHIM_WARN, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while(0) +#define SHIM_INFO(fmt, ...) do { if(g_ShimDebugLevel) ShimDbgPrint(SHIM_INFO, __FUNCTION__, fmt, ##__VA_ARGS__ ); } while(0) + + +/* sdbapi.c */ +void SdbpHeapInit(); +void SdbpHeapDeinit(); +#if SDBAPI_DEBUG_ALLOC + +LPVOID SdbpAlloc(SIZE_T size, int line, const char* file); +LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size, int line, const char* file); +void SdbpFree(LPVOID mem, int line, const char* file); + +#define SdbAlloc(size) SdbpAlloc(size, __LINE__, __FILE__) +#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size, __LINE__, __FILE__) +#define SdbFree(mem) SdbpFree(mem, __LINE__, __FILE__) + +#else + +LPVOID SdbpAlloc(SIZE_T size); +LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size); +void SdbpFree(LPVOID mem); + +#define SdbAlloc(size) SdbpAlloc(size) +#define SdbReAlloc(mem, size) SdbpReAlloc(mem, size) +#define SdbFree(mem) SdbpFree(mem) + +#endif Index: dll/win32/apphelp/apphelp.spec =================================================================== --- dll/win32/apphelp/apphelp.spec (revision 0) +++ dll/win32/apphelp/apphelp.spec (working copy) @@ -0,0 +1,175 @@ +@ stdcall AllowPermLayer(wstr) +@ stub ApphelpCheckExe +@ stub ApphelpCheckInstallShieldPackage +@ stub ApphelpCheckMsiPackage +@ stub ApphelpCheckRunApp +@ stub ApphelpCheckRunAppEx +@ stub ApphelpCheckShellObject +@ stub ApphelpCreateAppcompatData +@ stub ApphelpFixMsiPackage +@ stub ApphelpFixMsiPackageExe +@ stub ApphelpFreeFileAttributes +@ stub ApphelpGetFileAttributes +@ stub ApphelpGetMsiProperties +@ stub ApphelpGetNTVDMInfo +@ stub ApphelpParseModuleData +@ stub ApphelpQueryModuleData +@ stub ApphelpQueryModuleDataEx +@ stub ApphelpUpdateCacheEntry +@ stub GetPermLayers +@ stub SdbAddLayerTagRefToQuery +@ stub SdbApphelpNotify +@ stub SdbApphelpNotifyExSdbApphelpNotifyEx +@ stub SdbBeginWriteListTag +@ stub SdbBuildCompatEnvVariables +@ stub SdbCloseApphelpInformation +@ stub SdbCloseDatabase +@ stub SdbCloseDatabaseWrite +@ stub SdbCloseLocalDatabase +@ stub SdbCommitIndexes +@ stub SdbCreateDatabase +@ stub SdbCreateHelpCenterURL +@ stub SdbCreateMsiTransformFile +@ stub SdbDeclareIndex +@ stub SdbDumpSearchPathPartCaches +@ stub SdbEnumMsiTransforms +@ stub SdbEndWriteListTag +@ stub SdbEscapeApphelpURL +@ stub SdbFindFirstDWORDIndexedTag +@ stub SdbFindFirstMsiPackage +@ stub SdbFindFirstMsiPackage_Str +@ stub SdbFindFirstNamedTag +@ stub SdbFindFirstStringIndexedTag +@ stub SdbFindFirstTag +@ stub SdbFindFirstTagRef +@ stub SdbFindNextDWORDIndexedTag +@ stub SdbFindNextMsiPackage +@ stub SdbFindNextStringIndexedTag +@ stub SdbFindNextTag +@ stub SdbFindNextTagRef +@ stub SdbFreeDatabaseInformation +@ stub SdbFreeFileAttributes +@ stub SdbFreeFileInfo +@ stub SdbFreeFlagInfo +@ stub SdbGetAppCompatDataSize +@ stub SdbGetAppPatchDir +@ stub SdbGetBinaryTagData +@ stub SdbGetDatabaseID +@ stub SdbGetDatabaseInformation +@ stub SdbGetDatabaseInformationByName +@ stub SdbGetDatabaseMatch +@ stub SdbGetDatabaseVersion +@ stub SdbGetDllPath +@ stub SdbGetEntryFlags +@ stub SdbGetFileAttributes +@ stub SdbGetFileImageType +@ stub SdbGetFileImageTypeEx +@ stub SdbGetFileInfo +@ stub SdbGetFirstChild +@ stub SdbGetIndex +@ stub SdbGetItemFromItemRef +@ stub SdbGetLayerName +@ stub SdbGetLayerTagRef +@ stub SdbGetLocalPDB +@ stub SdbGetMatchingExe +@ stub SdbGetMsiPackageInformation +@ stub SdbGetNamedLayer +@ stub SdbGetNextChild +@ stub SdbGetNthUserSdb +@ stdcall SdbGetPermLayerKeys(wstr wstr ptr long) +@ stub SdbGetShowDebugInfoOption +@ stub SdbGetShowDebugInfoOptionValue +@ stub SdbGetStandardDatabaseGUID +@ stub SdbGetStringTagPtr +@ stub SdbGetTagDataSize +@ stub SdbGetTagFromTagID +@ stub SdbGrabMatchingInfo +@ stub SdbGrabMatchingInfoEx +@ stub SdbGUIDFromString +@ stub SdbGUIDToString +@ stub SdbInitDatabase +@ stub SdbInitDatabaseEx +@ stub SdbIsNullGUID +@ stub SdbIsStandardDatabase +@ stub SdbIsTagrefFromLocalDB +@ stub SdbIsTagrefFromMainDB +@ stub SdbLoadString +@ stub SdbMakeIndexKeyFromString +@ stub SdbOpenApphelpDetailsDatabase +@ stub SdbOpenApphelpDetailsDatabaseSP +@ stub SdbOpenApphelpInformation +@ stub SdbOpenApphelpInformationByID +@ stub SdbOpenApphelpResourceFile +@ stub SdbOpenDatabase +@ stub SdbOpenDbFromGuid +@ stub SdbOpenLocalDatabase +@ stub SdbPackAppCompatData +@ stub SdbQueryApphelpInformation +@ stub SdbQueryBlockUpgrade +@ stub SdbQueryContext +@ stub SdbQueryData +@ stub SdbQueryDataEx +@ stub SdbQueryDataExTagID +@ stub SdbQueryFlagInfo +@ stub SdbQueryName +@ stub SdbQueryReinstallUpgrade +@ stub SdbReadApphelpData +@ stub SdbReadApphelpDetailsData +@ stub SdbReadBinaryTag +@ stub SdbReadBYTETag +@ stub SdbReadDWORDTag +@ stub SdbReadDWORDTagRef +@ stub SdbReadEntryInformation +@ stub SdbReadMsiTransformInfo +@ stub SdbReadPatchBits +@ stub SdbReadQWORDTag +@ stub SdbReadQWORDTagRef +@ stub SdbReadStringTag +@ stub SdbReadStringTagRef +@ stub SdbReadWORDTag +@ stub SdbReadWORDTagRef +@ stub SdbRegisterDatabase +@ stub SdbReleaseDatabase +@ stub SdbReleaseMatchingExe +@ stub SdbResolveDatabase +@ stub SdbSetApphelpDebugParameters +@ stub SdbSetEntryFlags +@ stub SdbSetImageType +@ stdcall SdbSetPermLayerKeys(wstr wstr long) +@ stub SdbShowApphelpDialog +@ stub SdbShowApphelpFromQuery +@ stub SdbStartIndexing +@ stub SdbStopIndexing +@ stub SdbStringDuplicate +@ stub SdbStringReplace +@ stub SdbStringReplaceArray +@ stub SdbTagIDToTagRef +@ stub SdbTagRefToTagID +@ stub SdbTagToString +@ stub SdbUnregisterDatabase +@ stub SdbWriteBinaryTag +@ stub SdbWriteBinaryTagFromFile +@ stub SdbWriteBYTETag +@ stub SdbWriteDWORDTag +@ stub SdbWriteNULLTag +@ stub SdbWriteQWORDTag +@ stub SdbWriteStringRefTag +@ stub SdbWriteStringTag +@ stub SdbWriteStringTagDirect +@ stub SdbWriteWORDTag +@ stub SE_DllLoaded +@ stub SE_DllUnloaded +@ stub SE_GetHookAPIs +@ stub SE_GetMaxShimCount +@ stub SE_GetProcAddressLoad +@ stub SE_GetShimCount +@ stub SE_InstallAfterInit +@ stub SE_InstallBeforeInit +@ stub SE_IsShimDll +@ stub SE_LdrEntryRemoved +@ stub SE_ProcessDying +@ stub SetPermLayers +@ cdecl ShimDbgPrint(long str str) +@ stub ShimDumpCache +@ stub ShimFlushCache +@ stdcall SetPermLayerState(wstr wstr long long long) Index: dll/win32/apphelp/layer.c =================================================================== --- dll/win32/apphelp/layer.c (revision 0) +++ dll/win32/apphelp/layer.c (working copy) @@ -0,0 +1,552 @@ +/* + * 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 + */ + +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "strsafe.h" +#include +#include "apphelp.h" + +#define GPLK_USER 1 +#define GPLK_MACHINE 2 +#define MAX_LAYER_LENGTH 256 +#define LAYER_APPLY_TO_SYSTEM_EXES 1 +#define LAYER_UNK_FLAG2 2 + +#ifndef REG_SZ +#define REG_SZ 1 +#endif + +#if defined(__GNUC__) +#define APPCOMPAT_LAYER_KEY (const WCHAR[]){'\\','S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p','C','o','m','p','a','t','F','l','a','g','s','\\','L','a','y','e','r','s',0} +#define REGISTRY_MACHINE (const WCHAR[]){'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e',0} +#define SPACE_ONLY (const WCHAR[]){' ',0} +#define DISALLOWED_LAYER_CHARS (const WCHAR[]){' ','#','!',0} +#define LAYER_SEPARATORS (const WCHAR[]){' ','!',0} +#define SIGN_MEDIA_FMT (const WCHAR[]){'S','I','G','N','.','M','E','D','I','A','=','%','X',' ','%','s',0} + +#else +#define APPCOMPAT_LAYER_KEY L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers" +#define REGISTRY_MACHINE L"\\Registry\\Machine" +#define SPACE_ONLY L" " +#define DISALLOWED_LAYER_CHARS L" #!" +#define LAYER_SEPARATORS L" \t" +#define SIGN_MEDIA_FMT L"SIGN.MEDIA=%X %s" +#endif + + +typedef struct SDB_TMP_STR +{ + UNICODE_STRING Str; + WCHAR FixedBuffer[MAX_PATH]; +} SDB_TMP_STR, *PSDB_TMP_STR; + +void SdbpInitTempStr(PSDB_TMP_STR String) +{ + String->Str.Buffer = String->FixedBuffer; + String->Str.Length = 0; + String->Str.MaximumLength = sizeof(String->FixedBuffer); +} + +void SdbpFreeTempStr(PSDB_TMP_STR String) +{ + if (String->Str.Buffer != String->FixedBuffer) + { + SdbFree(String->Str.Buffer); + } +} + +void SdbpResizeTempStr(PSDB_TMP_STR String, WORD newLength) +{ + if(newLength > String->Str.MaximumLength) + { + SdbpFreeTempStr(String); + String->Str.MaximumLength = newLength * sizeof(WCHAR); + String->Str.Buffer = SdbAlloc(String->Str.MaximumLength); + String->Str.Length = 0; + } +} + +BOOL SdbpGetLongPathName(PCWSTR wszPath, PSDB_TMP_STR Result) +{ + DWORD max = Result->Str.MaximumLength / 2; + DWORD ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max); + if (ret) + { + if (ret >= max) + { + SdbpResizeTempStr(Result, ret); + max = Result->Str.MaximumLength / 2; + ret = GetLongPathNameW(wszPath, Result->Str.Buffer, max); + } + if (ret && ret < max) + { + Result->Str.Length = ret * 2; + return TRUE; + } + } + SHIM_ERR("Failed to convert short path to long path error 0x%lx\n", GetLastError()); + return FALSE; +} + +BOOL SdbpIsPathOnRemovableMedia(PCWSTR Path) +{ + WCHAR tmp[4] = { 'A',':','\\',0 }; + ULONG type; + if (!Path) + { + SHIM_ERR("Invalid argument\n"); + return FALSE; + } + switch (Path[1]) + { + case L':': + break; + case L'\\': + SHIM_INFO("\"%S\" is a network path.\n", Path); + return FALSE; + default: + SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path); + return FALSE; + } + tmp[0] = Path[0]; + type = GetDriveTypeW(tmp); + + return type == DRIVE_REMOVABLE || type == DRIVE_CDROM; +} + +BOOL SdbpBuildSignMediaId(PSDB_TMP_STR LongPath) +{ + SDB_TMP_STR Scratch; + PWCHAR Ptr; + + SdbpInitTempStr(&Scratch); + SdbpResizeTempStr(&Scratch, LongPath->Str.Length / sizeof(WCHAR)+30); + StringCbCopyNW(Scratch.Str.Buffer, Scratch.Str.MaximumLength, LongPath->Str.Buffer, LongPath->Str.Length); + Ptr = wcsrchr(LongPath->Str.Buffer, '\\'); + if (Ptr) + { + HANDLE FindHandle; + WIN32_FIND_DATAW FindData; + Ptr[1] = '*'; + Ptr[2] = '\0'; + FindHandle = FindFirstFileW(LongPath->Str.Buffer, &FindData); + if (FindHandle != INVALID_HANDLE_VALUE) + { + DWORD SignMedia = 0; + do { + if (!(FindData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && FindData.nFileSizeLow) + SignMedia = SignMedia << 1 ^ FindData.nFileSizeLow; + } while (FindNextFileW(FindHandle, &FindData)); + + FindClose(FindHandle); + SdbpResizeTempStr(LongPath, (LongPath->Str.Length >> 1) + (20)); + StringCbPrintfW(LongPath->Str.Buffer, LongPath->Str.MaximumLength, SIGN_MEDIA_FMT, SignMedia, Scratch.Str.Buffer + 3); + LongPath->Str.Length = wcslen(LongPath->Str.Buffer) * sizeof(WCHAR); + SdbpFreeTempStr(&Scratch); + return TRUE; + } + } + SdbpFreeTempStr(&Scratch); + SdbpFreeTempStr(LongPath); + return FALSE; +} + +BOOL SdbpResolvePath(PSDB_TMP_STR LongPath, PCWSTR wszPath) +{ + SdbpInitTempStr(LongPath); + if (!SdbpGetLongPathName(wszPath, LongPath)) + { + SdbpFreeTempStr(LongPath); + return FALSE; + } + if (SdbpIsPathOnRemovableMedia(LongPath->Str.Buffer)) + { + return SdbpBuildSignMediaId(LongPath); + } + return TRUE; +} + +static ACCESS_MASK g_QueryFlag = 0xffffffff; +ACCESS_MASK QueryFlag() +{ + 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; +} + +HRESULT SdbpOpenKey(PUNICODE_STRING FullPath, BOOL bMachine, ACCESS_MASK Access, PHANDLE KeyHandle) +{ + UNICODE_STRING BasePath; + const WCHAR* LayersKey = APPCOMPAT_LAYER_KEY; + OBJECT_ATTRIBUTES ObjectLayer = RTL_INIT_OBJECT_ATTRIBUTES(FullPath, OBJ_CASE_INSENSITIVE); + HRESULT hr = E_FAIL; + FullPath->Buffer = NULL; + FullPath->Length = FullPath->MaximumLength = 0; + if (bMachine) + { + RtlInitUnicodeString(&BasePath, REGISTRY_MACHINE); + } + else + { + hr = RtlFormatCurrentUserKeyPath(&BasePath); + if (!SUCCEEDED(hr)) + { + SHIM_ERR("Unable to aquire user registry key, Error: 0x%lx\n", hr); + return hr; + } + } + FullPath->MaximumLength = BasePath.Length + wcslen(LayersKey) * sizeof(WCHAR)+sizeof(WCHAR); + FullPath->Buffer = SdbAlloc(FullPath->MaximumLength); + FullPath->Length = 0; + RtlAppendUnicodeStringToString(FullPath, &BasePath); + if (!bMachine) + RtlFreeUnicodeString(&BasePath); + RtlAppendUnicodeToString(FullPath, LayersKey); + + hr = NtOpenKey(KeyHandle, Access | QueryFlag(), &ObjectLayer); + if (FAILED(hr)) + { + SHIM_ERR("Unable to open Key \"%wZ\" Status 0x%lx\n", FullPath, hr); + SdbFree(FullPath->Buffer); + FullPath->Buffer = NULL; + } + return hr; +} + + +BOOL SdbpGetPermLayersInternal(PUNICODE_STRING FullPath, PWSTR pwszLayers, PDWORD pdwBytes, BOOL bMachine) +{ + UNICODE_STRING FullKey; + CHAR ValueBuffer[MAX_LAYER_LENGTH * sizeof(WCHAR)+sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; + PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer; + ULONG Length = 0; + HANDLE KeyHandle; + HRESULT hr; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_QUERY_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtQueryValueKey(KeyHandle, FullPath, KeyValuePartialInformation, PartialInfo, sizeof(ValueBuffer), &Length); + if (SUCCEEDED(hr)) + { + StringCbCopyNW(pwszLayers, *pdwBytes, (PCWSTR)PartialInfo->Data, PartialInfo->DataLength); + *pdwBytes = PartialInfo->DataLength; + } + else + { + SHIM_INFO("Failed to read value info from Key \"%wZ\" Status 0x%lx\n", &FullKey, hr); + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + return SUCCEEDED(hr); +} + +BOOL SdbDeletePermLayerKeys(PCWSTR wszPath, BOOL bMachine) +{ + UNICODE_STRING FullKey; + SDB_TMP_STR LongPath; + HANDLE KeyHandle; + HRESULT hr; + + if (!SdbpResolvePath(&LongPath, wszPath)) + return FALSE; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtDeleteValueKey(KeyHandle, &LongPath.Str); + if (!SUCCEEDED(hr)) + { + SHIM_INFO("Failed to delete value from Key \"%wZ\" Status 0x%lx\n", &FullKey, hr); + /* This is what we want, so if the key didnt exist, we should not fail :) */ + if (hr == STATUS_OBJECT_NAME_NOT_FOUND) + hr = S_OK; + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + SdbpFreeTempStr(&LongPath); + return SUCCEEDED(hr); +} + +BOOL SdbpMatchLayer(PCWSTR start, PCWSTR end, PCWSTR compare) +{ + size_t len; + if(!end) + return !wcsicmp(start, compare); + len = end-start; + return wcslen(compare) == len && !_wcsnicmp(start, compare, len); +} + +BOOL SdbpAppendLayer(PWSTR target, DWORD len, PCWSTR layer, PCWSTR end) +{ + HRESULT hr = S_OK; + if (target[0]) + hr = StringCbCatW(target, len, SPACE_ONLY); + + if(SUCCEEDED(hr)) + { + if (end) + hr = StringCbCatNW(target, len, layer, (end-layer) * sizeof(WCHAR)); + else + hr = StringCbCatW(target, len, layer); + } + + return SUCCEEDED(hr); +} + + +/** + * Determine if we allow permission layers to apply on this file. + * + * @param [in] Path Full pathname of the file, only the drive part is used. + * + * @return TRUE if we allow permission layer, FALSE if not. + */ +BOOL WINAPI AllowPermLayer(PCWSTR Path) +{ + WCHAR tmp[4] = { 'A',':','\\', 0 }; + ULONG type; + if (!Path) + { + SHIM_ERR("Invalid argument\n"); + return FALSE; + } + switch (Path[1]) + { + case L':': + break; + case L'\\': + SHIM_INFO("\"%S\" is a network path.\n", Path); + return FALSE; + default: + SHIM_INFO("\"%S\" not a full path we can operate on.\n", Path); + return FALSE; + } + tmp[0] = Path[0]; + type = GetDriveTypeW(tmp); + if (type == DRIVE_REMOTE) + { + /* The logging here indicates that it does not like a CDROM or removable media, but it only + seems to bail out on a media that reports it is remote... + I have included correct logging, I doubt anyone would parse the logging, so this shouldnt break anything. */ + SHIM_INFO("\"%S\" is on a remote drive.\n", Path); + return FALSE; + } + return TRUE; +} + +/** + * Read the layers specified for the application. + * + * @param [in] wszPath Full pathname of the file. + * @param [out] pwszLayers On return, the layers set on the file. + * @param pdwBytes The size of the pwszLayers buffer in bytes, and on return the size of + * the data written (in bytes) + * @param [in] dwFlags The flags, [GPLK_USER | GPLK_MACHINE]. + * + * @return TRUE if it succeeds, FALSE if it fails. + */ +BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwBytes, DWORD dwFlags) +{ + BOOL Result = FALSE; + SDB_TMP_STR LongPath; + DWORD dwBytes, dwTotal = 0; + if (!wszPath || !pdwBytes) + { + SHIM_ERR("NULL parameter passed for wszPath or pdwBytes.\n"); + return FALSE; + } + + if (!SdbpResolvePath(&LongPath, wszPath)) + return FALSE; + dwBytes = *pdwBytes; + if (dwFlags & GPLK_MACHINE) + { + if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, TRUE)) + { + Result = TRUE; + dwTotal = dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */ + pwszLayers += dwTotal / sizeof(WCHAR); + dwBytes = *pdwBytes - dwBytes; + if (dwFlags & GPLK_USER) + { + *(pwszLayers++) = L' '; + *pwszLayers = L'\0'; + dwBytes -= sizeof(WCHAR); + dwTotal += sizeof(WCHAR); + } + } + } + if (dwFlags & GPLK_USER) + { + if (SdbpGetPermLayersInternal(&LongPath.Str, pwszLayers, &dwBytes, FALSE)) + { + Result = TRUE; + dwTotal += dwBytes - sizeof(WCHAR); /* Compensate for the nullterm. */ + } + else if (dwTotal > 0 && pwszLayers[-1] == L' ') + { + pwszLayers[-1] = '\0'; + dwTotal -= sizeof(WCHAR); + } + } + if (dwTotal) + dwTotal += sizeof(WCHAR); + *pdwBytes = dwTotal; + SdbpFreeTempStr(&LongPath); + return Result; +} + +/** + * Set or clear the Layer key. + * + * @param [in] wszPath Full pathname of the file. + * @param [in] wszLayers The layers to add (space separated), or an empty string / NULL to + * remove all layers. + * @param [in] bMachine TRUE to machine. + * + * @return TRUE if it succeeds, FALSE if it fails. + */ +BOOL WINAPI SdbSetPermLayerKeys(PCWSTR wszPath, PCWSTR wszLayers, BOOL bMachine) +{ + UNICODE_STRING FullKey; + SDB_TMP_STR LongPath; + HANDLE KeyHandle; + HRESULT hr; + + if (!wszLayers || *wszLayers == '\0') + return SdbDeletePermLayerKeys(wszPath, bMachine); + + if (!SdbpResolvePath(&LongPath, wszPath)) + return FALSE; + + hr = SdbpOpenKey(&FullKey, bMachine, KEY_SET_VALUE, &KeyHandle); + if (SUCCEEDED(hr)) + { + hr = NtSetValueKey(KeyHandle, &LongPath.Str, 0, REG_SZ, (PVOID)wszLayers, wcslen(wszLayers) * sizeof(WCHAR)+sizeof(WCHAR)); + if (!SUCCEEDED(hr)) + { + SHIM_INFO("Failed to write a value to Key \"%wZ\" Status 0x%lx\n", &FullKey, hr); + if (hr == STATUS_OBJECT_NAME_NOT_FOUND) + hr = S_OK; + } + NtClose(KeyHandle); + SdbFree(FullKey.Buffer); + } + SdbpFreeTempStr(&LongPath); + return SUCCEEDED(hr); +} + +/** + * Adds or removes a single layer entry. + * + * @param [in] wszPath Full pathname of the file. + * @param [in] wszLayer The layer to add or remove. + * @param [in] dwFlags Additional flags to add / remove [LAYER_APPLY_TO_SYSTEM_EXES | ???]. + * @param [in] bMachine When TRUE, the setting applies to all users, when FALSE only applies + * to the current user. + * @param [in] bEnable TRUE to enable, FALSE to disable a layer / flag specified. + * + * @return TRUE if it succeeds, FALSE if it fails. + */ +BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable) +{ + WCHAR fullLayer[MAX_LAYER_LENGTH] = { 0 }; + WCHAR newLayer[MAX_LAYER_LENGTH] = { 0 }; + DWORD dwBytes = sizeof(fullLayer), dwWriteFlags = 0; + PWSTR start, p; + + if (!wszLayer) + { + SHIM_ERR("Invalid argument\n"); + return FALSE; + } + if (dwFlags & ~(LAYER_APPLY_TO_SYSTEM_EXES | LAYER_UNK_FLAG2)) + { + SHIM_ERR("Invalid flags\n"); + return FALSE; + } + p = wcspbrk(wszLayer, DISALLOWED_LAYER_CHARS); + if(p) + { + switch(*p) + { + case ' ': + SHIM_ERR("Only one layer can be passed in at a time.\n"); + return FALSE; + case '#': + case '!': + SHIM_ERR("Flags cannot be passed in with the layer name.\n"); + return FALSE; + } + } + if (!SdbGetPermLayerKeys(wszPath, fullLayer, &dwBytes, bMachine ? GPLK_MACHINE : GPLK_USER)) + { + fullLayer[0] = '\0'; + dwBytes = sizeof(fullLayer); + } + + start = fullLayer; + while (*start == '!' || *start == '#' || *start == ' ' || *start == '\t') + { + if (*start == '#') + dwWriteFlags |= LAYER_APPLY_TO_SYSTEM_EXES; + else if (*start == '!') + dwWriteFlags |= LAYER_UNK_FLAG2; + start++; + } + if (bEnable) + dwWriteFlags |= dwFlags; + else + dwWriteFlags &= ~dwFlags; + + p = newLayer; + if (dwWriteFlags & LAYER_UNK_FLAG2) + *(p++) = '!'; + if (dwWriteFlags & LAYER_APPLY_TO_SYSTEM_EXES) + *(p++) = '#'; + + do { + while (*start == ' ' || *start == '\t') + ++start; + + if (*start == '\0') + break; + p = wcspbrk(start, LAYER_SEPARATORS); + if (!SdbpMatchLayer(start, p, wszLayer)) + { + SdbpAppendLayer(newLayer, sizeof(newLayer), start, p); + } + start = p + 1; + } while (p); + + if (bEnable && wszLayer[0]) + { + SdbpAppendLayer(newLayer, sizeof(newLayer), wszLayer, NULL); + } + + return SdbSetPermLayerKeys(wszPath, newLayer, bMachine); +} Index: dll/win32/apphelp/sdbapi.c =================================================================== --- dll/win32/apphelp/sdbapi.c (revision 0) +++ dll/win32/apphelp/sdbapi.c (working copy) @@ -0,0 +1,202 @@ +/* + * Copyright 2011 André Hentschel + * Copyright 2013 Mislav Blaževic + * 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 + */ + +#define WIN32_NO_STATUS +#include "windows.h" +#include "ntndk.h" +#include "strsafe.h" +#include "apphelp.h" + +#include "wine/unicode.h" + + +static HANDLE SdbpHeap(); + +#if SDBAPI_DEBUG_ALLOC + +typedef struct SHIM_ALLOC_ENTRY +{ + PVOID Address; + SIZE_T Size; + int Line; + const char* File; + PVOID Next; + PVOID Prev; +} SHIM_ALLOC_ENTRY, *PSHIM_ALLOC_ENTRY; + + +static RTL_AVL_TABLE g_SdbpAllocationTable; + + +static RTL_GENERIC_COMPARE_RESULTS +NTAPI ShimAllocCompareRoutine( _In_ PRTL_AVL_TABLE Table, _In_ PVOID FirstStruct, _In_ PVOID SecondStruct) +{ + PVOID First = ((PSHIM_ALLOC_ENTRY)FirstStruct)->Address; + PVOID Second = ((PSHIM_ALLOC_ENTRY)SecondStruct)->Address; + + if (First < Second) + return GenericLessThan; + else if (First == Second) + return GenericEqual; + return GenericGreaterThan; +} + +static PVOID NTAPI ShimAllocAllocateRoutine( _In_ PRTL_AVL_TABLE Table, _In_ CLONG ByteSize) +{ + return HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, ByteSize); +} + +static VOID NTAPI ShimAllocFreeRoutine( _In_ PRTL_AVL_TABLE Table, _In_ PVOID Buffer) +{ + HeapFree(SdbpHeap(), 0, Buffer); +} + +static void SdbpInsertAllocation(PVOID address, SIZE_T size, int line, const char* file) +{ + SHIM_ALLOC_ENTRY Entry = {0}; + + Entry.Address = address; + Entry.Size = size; + Entry.Line = line; + Entry.File = file; + RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Entry, sizeof(Entry), NULL); +} + +static void SdbpUpdateAllocation(PVOID address, PVOID newaddress, SIZE_T size, int line, const char* file) +{ + SHIM_ALLOC_ENTRY Lookup = {0}; + PSHIM_ALLOC_ENTRY Entry; + Lookup.Address = address; + Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup); + + if(address == newaddress) + Entry->Size = size; + else + { + Lookup.Address = newaddress; + Lookup.Size = size; + Lookup.Line = line; + Lookup.File = file; + Lookup.Prev = address; + RtlInsertElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup, sizeof(Lookup), NULL); + Entry->Next = newaddress; + } +} + +static void SdbpRemoveAllocation(PVOID address, int line, const char* file) +{ + char buf[512]; + SHIM_ALLOC_ENTRY Lookup = {0}; + PSHIM_ALLOC_ENTRY Entry; + + sprintf(buf, "\r\n===============\r\n%s(%d): SdbpFree called, tracing alloc:\r\n", file, line); + OutputDebugStringA(buf); + + Lookup.Address = address; + while (Lookup.Address) + { + Entry = RtlLookupElementGenericTableAvl(&g_SdbpAllocationTable, &Lookup); + if (Entry) + { + Lookup = *Entry; + RtlDeleteElementGenericTableAvl(&g_SdbpAllocationTable, Entry); + + sprintf(buf, " > %s(%d): %s%sAlloc( %d ) ==> %p\r\n", Lookup.File, Lookup.Line, + Lookup.Next ? "Invalidated " : "", Lookup.Prev ? "Re" : "", Lookup.Size, Lookup.Address); + OutputDebugStringA(buf); + Lookup.Address = Lookup.Prev; + } + else + { + Lookup.Address = NULL; + } + } + sprintf(buf, "\r\n===============\r\n"); + OutputDebugStringA(buf); +} + +#endif + +static HANDLE g_Heap; +void SdbpHeapInit() +{ +#if SDBAPI_DEBUG_ALLOC + RtlInitializeGenericTableAvl(&g_SdbpAllocationTable, ShimAllocCompareRoutine, + ShimAllocAllocateRoutine, ShimAllocFreeRoutine, NULL); +#endif + g_Heap = HeapCreate(0, 0x10000, 0); +} + +void SdbpHeapDeinit() +{ +#if SDBAPI_DEBUG_ALLOC + if(g_SdbpAllocationTable.NumberGenericTableElements != 0) + __debugbreak(); +#endif + HeapDestroy(g_Heap); +} + +DWORD SdbpStrlen(PCWSTR string) +{ + return (lstrlenW(string) + 1) * sizeof(WCHAR); +} + +static HANDLE SdbpHeap() +{ + return g_Heap; +} + +LPVOID SdbpAlloc(SIZE_T size +#if SDBAPI_DEBUG_ALLOC + , int line, const char* file +#endif + ) +{ + LPVOID mem = HeapAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, size); +#if SDBAPI_DEBUG_ALLOC + SdbpInsertAllocation(mem, size, line, file); +#endif + return mem; +} + +LPVOID SdbpReAlloc(LPVOID mem, SIZE_T size +#if SDBAPI_DEBUG_ALLOC + , int line, const char* file +#endif + ) +{ + LPVOID newmem = HeapReAlloc(SdbpHeap(), HEAP_ZERO_MEMORY, mem, size); +#if SDBAPI_DEBUG_ALLOC + SdbpUpdateAllocation(mem, newmem, size, line, file); +#endif + return newmem; +} + +void SdbpFree(LPVOID mem +#if SDBAPI_DEBUG_ALLOC + , int line, const char* file +#endif + ) +{ +#if SDBAPI_DEBUG_ALLOC + SdbpRemoveAllocation(mem, line, file); +#endif + HeapFree(SdbpHeap(), 0, mem); +} Index: dll/win32/CMakeLists.txt =================================================================== --- dll/win32/CMakeLists.txt (revision 69817) +++ dll/win32/CMakeLists.txt (working copy) @@ -5,6 +5,7 @@ add_subdirectory(actxprxy) add_subdirectory(advapi32) add_subdirectory(advpack) +add_subdirectory(apphelp) add_subdirectory(atl) add_subdirectory(atl100) add_subdirectory(atl80) Index: modules/rostests/winetests/apphelp/CMakeLists.txt =================================================================== --- modules/rostests/winetests/apphelp/CMakeLists.txt (revision 0) +++ modules/rostests/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: modules/rostests/winetests/apphelp/layerapi.c =================================================================== --- modules/rostests/winetests/apphelp/layerapi.c (revision 0) +++ modules/rostests/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: modules/rostests/winetests/apphelp/testlist.c =================================================================== --- modules/rostests/winetests/apphelp/testlist.c (revision 0) +++ modules/rostests/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: modules/rostests/winetests/CMakeLists.txt =================================================================== --- modules/rostests/winetests/CMakeLists.txt (revision 69817) +++ modules/rostests/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)