1 /* 2 * Copyright 2018 Fabian Maurer 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include <stdio.h> 20 21 #define COBJMACROS 22 23 #include <windows.h> 24 #include <winsxs.h> 25 #include <corerror.h> 26 #include "shlwapi.h" 27 28 #include "wine/test.h" 29 #include "wine/heap.h" 30 31 #include "initguid.h" 32 #include "interfaces.h" 33 34 #define SXS_LOOKUP_CLR_GUID_USE_ACTCTX 0x00000001 35 #define SXS_LOOKUP_CLR_GUID_FIND_SURROGATE 0x00010000 36 #define SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS 0x00020000 37 #define SXS_LOOKUP_CLR_GUID_FIND_ANY (SXS_LOOKUP_CLR_GUID_FIND_SURROGATE | SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS) 38 39 #define SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE 0x00000001 40 #define SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS 0x00000002 41 42 typedef struct _SXS_GUID_INFORMATION_CLR 43 { 44 DWORD cbSize; 45 DWORD dwFlags; 46 PCWSTR pcwszRuntimeVersion; 47 PCWSTR pcwszTypeName; 48 PCWSTR pcwszAssemblyIdentity; 49 } SXS_GUID_INFORMATION_CLR; 50 51 /* Defined in sxs.dll, but not found in any header */ 52 BOOL WINAPI SxsLookupClrGuid(DWORD flags, GUID *clsid, HANDLE actctx, void *buffer, SIZE_T buffer_len, SIZE_T *buffer_len_required); 53 54 static BOOL write_resource_file(const char *path_tmp, const char *name_res, const char *name_file, char *path_file) 55 { 56 HRSRC rsrc; 57 void *rsrc_data; 58 DWORD rsrc_size; 59 BOOL ret; 60 HANDLE hfile; 61 62 path_file[0] = 0; 63 rsrc = FindResourceA(GetModuleHandleA(NULL), name_res, (LPCSTR)RT_RCDATA); 64 if (!rsrc) return FALSE; 65 66 rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc)); 67 if (!rsrc_data) return FALSE; 68 69 rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc); 70 if (!rsrc_size) return FALSE; 71 72 strcpy(path_file, path_tmp); 73 PathAppendA(path_file, name_file); 74 hfile = CreateFileA(path_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 75 if (hfile == INVALID_HANDLE_VALUE) return FALSE; 76 77 ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL); 78 79 CloseHandle(hfile); 80 return ret; 81 } 82 83 static void run_test(void) 84 { 85 SIZE_T buffer_size; 86 BOOL ret; 87 SXS_GUID_INFORMATION_CLR *info; 88 WCHAR expected_type_name[] = {'D','L','L','.','T','e','s','t',0}; 89 WCHAR expected_runtime_version[] = {'v','4','.','0','.','0','.','0',0}; 90 WCHAR expected_assembly_identity[] = {'c','o','m','t','e','s','t',',','t','y','p','e','=','"','w','i','n','3','2','"',',','v','e','r','s','i','o','n','=','"','1','.','0','.','0','.','0','"',0}; 91 92 ret = SxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, NULL, 0, &buffer_size); 93 ok(ret == FALSE, "Got %d\n", ret); 94 ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got %d\n", GetLastError()); 95 96 info = heap_alloc(buffer_size); 97 ret = SxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, info, buffer_size, &buffer_size); 98 ok(ret == TRUE, "Got %d\n", ret); 99 ok(GetLastError() == 0, "Got %d\n", GetLastError()); 100 101 ok(info->dwFlags == SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS, "Got %d\n", info->dwFlags); 102 ok(lstrcmpW(info->pcwszTypeName, expected_type_name) == 0, "Got %s\n", 103 wine_dbgstr_w(info->pcwszTypeName)); 104 ok(lstrcmpW(info->pcwszAssemblyIdentity, expected_assembly_identity) == 0, "Got %s\n", 105 wine_dbgstr_w(info->pcwszAssemblyIdentity)); 106 ok(lstrcmpW(info->pcwszRuntimeVersion, expected_runtime_version) == 0, "Got %s\n", 107 wine_dbgstr_w(info->pcwszRuntimeVersion)); 108 109 heap_free(info); 110 } 111 112 static void prepare_and_run_test(void) 113 { 114 char path_tmp[MAX_PATH]; 115 char path_manifest_dll[MAX_PATH]; 116 char path_manifest_exe[MAX_PATH]; 117 BOOL success; 118 ACTCTXA context = {0}; 119 ULONG_PTR cookie; 120 HANDLE handle_context = INVALID_HANDLE_VALUE; 121 122 GetTempPathA(MAX_PATH, path_tmp); 123 124 if (!write_resource_file(path_tmp, "comtest_exe.manifest", "exe.manifest", path_manifest_exe)) 125 { 126 ok(0, "Failed to create file for testing\n"); 127 goto cleanup; 128 } 129 130 if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll)) 131 { 132 ok(0, "Failed to create file for testing\n"); 133 goto cleanup; 134 } 135 136 context.cbSize = sizeof(ACTCTXA); 137 context.lpSource = path_manifest_exe; 138 context.lpAssemblyDirectory = path_tmp; 139 context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; 140 141 handle_context = CreateActCtxA(&context); 142 ok(handle_context != INVALID_HANDLE_VALUE, "CreateActCtxA failed: %d\n", GetLastError()); 143 144 if (handle_context == INVALID_HANDLE_VALUE) 145 { 146 ok(0, "Failed to create activation context\n"); 147 goto cleanup; 148 } 149 150 success = ActivateActCtx(handle_context, &cookie); 151 ok(success, "ActivateActCtx failed: %d\n", GetLastError()); 152 153 run_test(); 154 155 cleanup: 156 if (handle_context != INVALID_HANDLE_VALUE) 157 { 158 success = DeactivateActCtx(0, cookie); 159 ok(success, "DeactivateActCtx failed: %d\n", GetLastError()); 160 ReleaseActCtx(handle_context); 161 } 162 if (*path_manifest_exe) 163 { 164 success = DeleteFileA(path_manifest_exe); 165 ok(success, "DeleteFileA failed: %d\n", GetLastError()); 166 } 167 if(*path_manifest_dll) 168 { 169 success = DeleteFileA(path_manifest_dll); 170 ok(success, "DeleteFileA failed: %d\n", GetLastError()); 171 } 172 } 173 174 static void run_child_process(void) 175 { 176 char cmdline[MAX_PATH]; 177 char exe[MAX_PATH]; 178 char **argv; 179 PROCESS_INFORMATION pi; 180 STARTUPINFOA si = { 0 }; 181 BOOL ret; 182 183 winetest_get_mainargs(&argv); 184 185 if (strstr(argv[0], ".exe")) 186 sprintf(exe, "%s", argv[0]); 187 else 188 sprintf(exe, "%s.exe", argv[0]); 189 sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], "subtest"); 190 191 si.cb = sizeof(si); 192 ret = CreateProcessA(exe, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 193 ok(ret, "Could not create process: %u\n", GetLastError()); 194 195 winetest_wait_child_process(pi.hProcess); 196 197 CloseHandle(pi.hThread); 198 CloseHandle(pi.hProcess); 199 } 200 201 static void test_SxsLookupClrGuid(void) 202 { 203 SIZE_T buffer_size; 204 BOOL ret; 205 206 ret = SxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, NULL, 0, &buffer_size); 207 ok(ret == FALSE, "Expected FALSE, got %d\n", ret); 208 ok(GetLastError() == ERROR_NOT_FOUND, "Expected ERROR_NOT_FOUND, got %d\n", GetLastError()); 209 210 run_child_process(); 211 } 212 213 START_TEST(sxs) 214 { 215 char **argv; 216 int argc = winetest_get_mainargs(&argv); 217 if (argc > 2) 218 { 219 prepare_and_run_test(); 220 return; 221 } 222 223 test_SxsLookupClrGuid(); 224 } 225