2 * Unit test suite for virtual substituted drive functions.
4 * Copyright 2017 Giannis Adamopoulos
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define STRSECTION_MAGIC 0x64487353 /* dHsS */
25 struct strsection_header
37 struct wndclass_redirect_data
42 ULONG name_offset
; /* versioned name offset */
44 ULONG module_offset
; /* container name offset to the section base */
47 struct dllredirect_data
60 DWORD ulEncodedAssemblyIdentityLength
;
61 DWORD ulEncodedAssemblyIdentityOffset
; /* offset to the section base */
62 DWORD ulManifestPathType
;
63 DWORD ulManifestPathLength
;
64 DWORD ulManifestPathOffset
; /* offset to the section base */
65 LARGE_INTEGER liManifestLastWriteTime
;
67 DWORD ulAssemblyDirectoryNameLength
;
68 DWORD ulAssemblyDirectoryNameOffset
; /* offset to the section base */
69 DWORD unk4
[3]; /* In win10 there are two more fields */
74 HANDLE
_CreateActCtxFromFile(LPCWSTR FileName
, int line
)
76 ACTCTXW ActCtx
= {sizeof(ACTCTX
)};
78 WCHAR buffer
[MAX_PATH
] , *separator
;
80 ok (GetModuleFileNameW(NULL
, buffer
, MAX_PATH
), "GetModuleFileName failed\n");
81 separator
= wcsrchr(buffer
, L
'\\');
83 wcscpy(separator
+ 1, FileName
);
85 ActCtx
.lpSource
= buffer
;
87 SetLastError(0xdeaddead);
88 h
= CreateActCtxW(&ActCtx
);
89 ok_(__FILE__
, line
)(h
!= INVALID_HANDLE_VALUE
, "CreateActCtx failed for %S\n", FileName
);
90 // In win10 last error is unchanged and in win2k3 it is ERROR_BAD_EXE_FORMAT
91 ok_(__FILE__
, line
)(GetLastError() == ERROR_BAD_EXE_FORMAT
|| GetLastError() == 0xdeaddead, "Wrong last error %lu\n", GetLastError());
96 VOID
_ActivateCtx(HANDLE h
, ULONG_PTR
*cookie
, int line
)
100 SetLastError(0xdeaddead);
101 res
= ActivateActCtx(h
, cookie
);
102 ok_(__FILE__
, line
)(res
== TRUE
, "ActivateActCtx failed\n");
103 ok_(__FILE__
, line
)(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD
)(0xdeaddead), GetLastError());
106 VOID
_DeactivateCtx(ULONG_PTR cookie
, int line
)
110 SetLastError(0xdeaddead);
111 res
= DeactivateActCtx(0, cookie
);
112 ok_(__FILE__
, line
)(res
== TRUE
, "DeactivateActCtx failed\n");
113 ok_(__FILE__
, line
)(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD
)(0xdeaddead), GetLastError());
116 void TestClassRedirection(HANDLE h
, LPCWSTR ClassToTest
, LPCWSTR ExpectedClassPart
, LPCWSTR ExpectedModule
, ULONG ExpectedClassCount
)
118 ACTCTX_SECTION_KEYED_DATA KeyedData
= { 0 };
120 struct strsection_header
*header
;
121 struct wndclass_redirect_data
*classData
;
122 LPCWSTR VersionedClass
, ClassLib
;
125 SetLastError(0xdeaddead);
126 KeyedData
.cbSize
= sizeof(KeyedData
);
127 res
= FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
129 ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION
,
132 ok(res
== TRUE
, "FindActCtxSectionString failed\n");
133 ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD
)(0xdeaddead), GetLastError());
135 ok(KeyedData
.ulDataFormatVersion
== 1, "Wrong format version: %lu\n", KeyedData
.ulDataFormatVersion
);
136 ok(KeyedData
.hActCtx
== h
, "Wrong handle\n");
137 ok(KeyedData
.lpSectionBase
!= NULL
, "Expected non null lpSectionBase\n");
138 ok(KeyedData
.lpData
!= NULL
, "Expected non null lpData\n");
139 header
= (struct strsection_header
*)KeyedData
.lpSectionBase
;
140 classData
= (struct wndclass_redirect_data
*)KeyedData
.lpData
;
142 if(res
== FALSE
|| KeyedData
.ulDataFormatVersion
!= 1 || header
== NULL
|| classData
== NULL
)
144 skip("Can't read data for class. Skipping\n");
148 ok(header
->magic
== STRSECTION_MAGIC
, "%lu\n", header
->magic
);
149 ok(header
->size
== sizeof(*header
), "Got %lu instead of %d\n", header
->size
, sizeof(*header
));
150 ok(header
->count
== ExpectedClassCount
, "Expected %lu classes, got %lu\n", ExpectedClassCount
, header
->count
);
152 VersionedClass
= (WCHAR
*)((BYTE
*)classData
+ classData
->name_offset
);
153 ClassLib
= (WCHAR
*)((BYTE
*)header
+ classData
->module_offset
);
154 data_lenght
= classData
->size
+ classData
->name_len
+ classData
->module_len
+ 2*sizeof(WCHAR
);
155 ok(KeyedData
.ulLength
== data_lenght
, "Got lenght %lu instead of %d\n", KeyedData
.ulLength
, data_lenght
);
156 ok(classData
->size
== sizeof(*classData
), "Got %lu instead of %d\n", classData
->size
, sizeof(*classData
));
157 ok(classData
->res
== 0, "Got res %lu\n", classData
->res
);
158 ok(classData
->module_len
== wcslen(ExpectedModule
) * 2, "Got name len %lu, expected %d\n", classData
->module_len
, wcslen(ExpectedModule
) *2);
159 ok(wcscmp(ClassLib
, ExpectedModule
) == 0, "Got %S, expected %S\n", ClassLib
, ExpectedModule
);
160 /* compare only if VersionedClass starts with ExpectedClassPart */
161 ok(memcmp(VersionedClass
, ExpectedClassPart
, sizeof(WCHAR
) * wcslen(ExpectedClassPart
)) == 0, "Expected %S to start with %S\n", VersionedClass
, ExpectedClassPart
);
165 VOID
TestLibDependency(HANDLE h
)
167 ACTCTX_SECTION_KEYED_DATA KeyedData
= { 0 };
169 struct strsection_header
*SectionHeader
;
170 struct dllredirect_data
*redirData
;
171 struct assemply_data
*assemplyData
;
173 SetLastError(0xdeaddead);
174 KeyedData
.cbSize
= sizeof(KeyedData
);
175 res
= FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
177 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION
,
180 ok(res
== TRUE
, "FindActCtxSectionString failed\n");
181 ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD
)(0xdeaddead), GetLastError());
183 ok(KeyedData
.ulDataFormatVersion
== 1, "Wrong format version: %lu", KeyedData
.ulDataFormatVersion
);
184 ok(KeyedData
.hActCtx
== h
, "Wrong handle\n");
185 ok(KeyedData
.lpSectionBase
!= NULL
, "Expected non null lpSectionBase\n");
186 ok(KeyedData
.lpData
!= NULL
, "Expected non null lpData\n");
187 SectionHeader
= (struct strsection_header
*)KeyedData
.lpSectionBase
;
188 redirData
= (struct dllredirect_data
*)KeyedData
.lpData
;
190 if(res
== FALSE
|| KeyedData
.ulDataFormatVersion
!= 1 || SectionHeader
== NULL
|| redirData
== NULL
)
192 skip("Can't read data for dep1.dll. Skipping\n");
196 ok(SectionHeader
->magic
== STRSECTION_MAGIC
, "%lu\n", SectionHeader
->magic
);
197 ok(SectionHeader
->size
== sizeof(*SectionHeader
), "Got %lu instead of %d\n", SectionHeader
->size
, sizeof(*SectionHeader
));
198 ok(SectionHeader
->count
== 2, "%lu\n", SectionHeader
->count
); /* 2 dlls? */
199 ok(redirData
->size
== sizeof(*redirData
), "Got %lu instead of %d\n", redirData
->size
, sizeof(*redirData
));
202 SetLastError(0xdeaddead);
203 KeyedData
.cbSize
= sizeof(KeyedData
);
204 res
= FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX
,
206 ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION
,
209 ok(res
== TRUE
, "FindActCtxSectionString failed\n");
210 ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD
)(0xdeaddead), GetLastError());
211 ok(KeyedData
.ulDataFormatVersion
== 1, "Wrong format version: %lu", KeyedData
.ulDataFormatVersion
);
212 ok(KeyedData
.hActCtx
== h
, "Wrong handle\n");
213 ok(KeyedData
.lpSectionBase
!= NULL
, "Expected non null lpSectionBase\n");
214 ok(KeyedData
.lpData
!= NULL
, "Expected non null lpData\n");
215 SectionHeader
= (struct strsection_header
*)KeyedData
.lpSectionBase
;
216 assemplyData
= (struct assemply_data
*)KeyedData
.lpData
;;
218 if(res
== FALSE
|| KeyedData
.ulDataFormatVersion
!= 1 || SectionHeader
== NULL
|| assemplyData
== NULL
)
220 skip("Can't read data for dep1. Skipping\n");
224 LPCWSTR AssemblyIdentity
, ManifestPath
, AssemblyDirectory
;
227 PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION details
= (PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION
)buffer
;
229 ok(SectionHeader
->magic
== STRSECTION_MAGIC
, "%lu\n", SectionHeader
->magic
);
230 ok(SectionHeader
->size
== sizeof(*SectionHeader
), "Got %lu instead of %d\n", SectionHeader
->size
, sizeof(*SectionHeader
));
231 ok(SectionHeader
->count
== 2, "%lu\n", SectionHeader
->count
); /* 2 dlls? */
233 data_lenght
= assemplyData
->size
+
234 assemplyData
->ulEncodedAssemblyIdentityLength
+
235 assemplyData
->ulManifestPathLength
+
236 assemplyData
->ulAssemblyDirectoryNameLength
+ 2 * sizeof(WCHAR
);
237 ok(assemplyData
->size
== sizeof(*assemplyData
), "Got %lu instead of %d\n", assemplyData
->size
, sizeof(*assemplyData
));
238 ok(KeyedData
.ulLength
== data_lenght
, "Got lenght %lu instead of %d\n", KeyedData
.ulLength
, data_lenght
);
240 AssemblyIdentity
= (WCHAR
*)((BYTE
*)SectionHeader
+ assemplyData
->ulEncodedAssemblyIdentityOffset
);
241 ManifestPath
= (WCHAR
*)((BYTE
*)SectionHeader
+ assemplyData
->ulManifestPathOffset
);
242 AssemblyDirectory
= (WCHAR
*)((BYTE
*)SectionHeader
+ assemplyData
->ulAssemblyDirectoryNameOffset
);
244 /* Use AssemblyDetailedInformationInActivationContext so as to infer the contents of assemplyData */
245 res
= QueryActCtxW(0, h
, &KeyedData
.ulAssemblyRosterIndex
,
246 AssemblyDetailedInformationInActivationContext
,
247 &buffer
, sizeof(buffer
), NULL
);
248 ok(res
== TRUE
, "QueryActCtxW failed\n");
249 ok(assemplyData
->ulFlags
== details
->ulFlags
, "\n");
250 ok(assemplyData
->ulEncodedAssemblyIdentityLength
== details
->ulEncodedAssemblyIdentityLength
, "\n");
251 ok(assemplyData
->ulManifestPathType
== details
->ulManifestPathType
, "\n");
252 ok(assemplyData
->ulManifestPathLength
== details
->ulManifestPathLength
, "\n");
253 ok(assemplyData
->ulAssemblyDirectoryNameLength
== details
->ulAssemblyDirectoryNameLength
, "\n");
254 ok(assemplyData
->liManifestLastWriteTime
.QuadPart
== details
->liManifestLastWriteTime
.QuadPart
, "\n");
256 ok(wcscmp(ManifestPath
, details
->lpAssemblyManifestPath
) == 0, "Expected path %S, got %S\n", details
->lpAssemblyManifestPath
, ManifestPath
);
257 ok(wcscmp(AssemblyDirectory
, details
->lpAssemblyDirectoryName
) == 0, "Expected path %S, got %S\n", details
->lpAssemblyManifestPath
, ManifestPath
);
259 /* It looks like that AssemblyIdentity isn't null terminated */
260 ok(memcmp(AssemblyIdentity
, details
->lpAssemblyEncodedAssemblyIdentity
, assemplyData
->ulEncodedAssemblyIdentityLength
) == 0, "Got wrong AssemblyIdentity\n");
264 START_TEST(FindActCtxSectionStringW
)
267 ULONG_PTR cookie
, cookie2
;
269 /*First run the redirection tests without using our own actctx */
270 TestClassRedirection(NULL
, L
"Button", L
"Button", L
"comctl32.dll", 27);
271 /* Something activates an activation context that mentions comctl32 but comctl32 is not loaded */
272 ok( GetModuleHandleW(L
"comctl32.dll") == NULL
, "Expected comctl32 not to be loaded\n");
273 ok( GetModuleHandleW(L
"user32.dll") == NULL
, "Expected user32 not to be loaded\n");
275 /* Class redirection tests */
276 h
= _CreateActCtxFromFile(L
"classtest.manifest", __LINE__
);
277 if (h
!= INVALID_HANDLE_VALUE
)
279 _ActivateCtx(h
, &cookie
, __LINE__
);
280 TestClassRedirection(h
, L
"Button", L
"2.2.2.2!Button", L
"testlib.dll", 5);
281 _ActivateCtx(NULL
, &cookie2
, __LINE__
);
282 TestClassRedirection(NULL
, L
"Button", L
"Button", L
"comctl32.dll", 27);
283 _DeactivateCtx(cookie2
, __LINE__
);
284 _DeactivateCtx(cookie
, __LINE__
);
288 skip("Failed to create context for classtest.manifest\n");
291 /* Class redirection tests with multiple contexts in the activation stack */
292 h2
= _CreateActCtxFromFile(L
"classtest2.manifest", __LINE__
);
293 if (h
!= INVALID_HANDLE_VALUE
&& h2
!= INVALID_HANDLE_VALUE
)
295 _ActivateCtx(h
, &cookie
, __LINE__
);
296 _ActivateCtx(h2
, &cookie2
, __LINE__
);
297 TestClassRedirection(NULL
, L
"Button", L
"Button", L
"comctl32.dll", 27);
298 TestClassRedirection(h2
, L
"MyClass", L
"1.1.1.1!MyClass", L
"testlib.dll", 5);
299 _DeactivateCtx(cookie2
, __LINE__
);
300 TestClassRedirection(h
, L
"Button", L
"2.2.2.2!Button", L
"testlib.dll", 5);
301 _DeactivateCtx(cookie
, __LINE__
);
305 skip("Failed to create context for classtest.manifest\n");
308 /* Dependency tests */
309 h
= _CreateActCtxFromFile(L
"deptest.manifest", __LINE__
);
310 if (h
!= INVALID_HANDLE_VALUE
)
312 _ActivateCtx(h
, &cookie
, __LINE__
);
313 TestLibDependency(h
);
314 _DeactivateCtx(cookie
, __LINE__
);
318 skip("Failed to create context for deptest.manifest\n");
321 /* Activate a context that depends on comctl32 v6 and run class tests again */
322 h
= _CreateActCtxFromFile(L
"comctl32dep.manifest", __LINE__
);
323 if (h
!= INVALID_HANDLE_VALUE
)
325 _ActivateCtx(h
, &cookie
, __LINE__
);
326 TestClassRedirection(h
, L
"Button", L
"6.0.", L
"comctl32.dll", 29);
327 ok( GetModuleHandleW(L
"comctl32.dll") == NULL
, "Expected comctl32 not to be loaded\n");
328 ok( GetModuleHandleW(L
"user32.dll") == NULL
, "Expected user32 not to be loaded\n");
329 _DeactivateCtx(cookie
, __LINE__
);
333 skip("Failed to create context for comctl32dep.manifest\n");