kernel32: Support activation context in SearchPath().

This commit is contained in:
Nikolay Sivov 2013-09-11 12:18:25 +04:00 committed by Alexandre Julliard
parent ce81f0809d
commit 41057a174d
2 changed files with 195 additions and 12 deletions

View File

@ -724,6 +724,97 @@ static inline BOOL contains_pathW (LPCWSTR name)
return (name[1] == '.' && (name[2] == '/' || name[2] == '\\'));
}
/***********************************************************************
* find_actctx_dllpath
*
* Find the path (if any) of the dll from the activation context.
* Returned path doesn't include a name.
*/
static NTSTATUS find_actctx_dllpath(const WCHAR *libname, WCHAR **path)
{
static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
ACTCTX_SECTION_KEYED_DATA data;
UNICODE_STRING nameW;
NTSTATUS status;
SIZE_T needed, size = 1024;
WCHAR *p;
RtlInitUnicodeString( &nameW, libname );
data.cbSize = sizeof(data);
status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
&nameW, &data );
if (status != STATUS_SUCCESS) return status;
for (;;)
{
if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
{
status = STATUS_NO_MEMORY;
goto done;
}
status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
AssemblyDetailedInformationInActivationContext,
info, size, &needed );
if (status == STATUS_SUCCESS) break;
if (status != STATUS_BUFFER_TOO_SMALL) goto done;
HeapFree( GetProcessHeap(), 0, info );
size = needed;
/* restart with larger buffer */
}
if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName)
{
status = STATUS_SXS_KEY_NOT_FOUND;
goto done;
}
if ((p = strrchrW( info->lpAssemblyManifestPath, '\\' )))
{
DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
p++;
if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
{
/* manifest name does not match directory name, so it's not a global
* windows/winsxs manifest; use the manifest directory name instead */
dirlen = p - info->lpAssemblyManifestPath;
needed = (dirlen + 1) * sizeof(WCHAR);
if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
*(p + dirlen) = 0;
goto done;
}
}
needed = (strlenW( DIR_Windows ) * sizeof(WCHAR) +
sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + 2*sizeof(WCHAR));
if (!(*path = p = HeapAlloc( GetProcessHeap(), 0, needed )))
{
status = STATUS_NO_MEMORY;
goto done;
}
strcpyW( p, DIR_Windows );
p += strlenW(p);
memcpy( p, winsxsW, sizeof(winsxsW) );
p += sizeof(winsxsW) / sizeof(WCHAR);
memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
*p++ = '\\';
*p = 0;
done:
HeapFree( GetProcessHeap(), 0, info );
RtlReleaseActivationContext( data.hActCtx );
return status;
}
/***********************************************************************
* SearchPathW [KERNEL32.@]
@ -802,15 +893,69 @@ DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen,
ret = RtlDosSearchPath_U( path, name, ext, buflen * sizeof(WCHAR),
buffer, lastpart ) / sizeof(WCHAR);
}
else /* search in the default path */
else /* search in active context and default path */
{
WCHAR *dll_path = MODULE_get_dll_load_path( NULL );
WCHAR *dll_path = NULL, *search = NULL;
DWORD req_len, name_len;
if (dll_path)
req_len = name_len = strlenW(name);
if (strchrW( name, '.' )) ext = NULL;
if (ext)
{
ret = RtlDosSearchPath_U( dll_path, name, ext, buflen * sizeof(WCHAR),
DWORD ext_len = strlenW(ext);
req_len += ext_len;
name_len += ext_len;
search = HeapAlloc( GetProcessHeap(), 0, (name_len + ext_len + 1) * sizeof(WCHAR) );
if (!search)
{
SetLastError( ERROR_OUTOFMEMORY );
HeapFree( GetProcessHeap(), 0, dll_path );
return 0;
}
strcpyW( search, name );
strcatW( search, ext );
name = search;
/* now that we have combined name we don't need extension any more */
}
/* When file is found with activation context no attempt is made
to check if it's really exist, path is returned only basing on context info. */
if (find_actctx_dllpath( name, &dll_path ) == STATUS_SUCCESS)
{
DWORD path_len;
path_len = strlenW(dll_path);
req_len += path_len;
if (lastpart) *lastpart = NULL;
/* count null termination char too */
if (req_len + 1 <= buflen)
{
memcpy( buffer, dll_path, path_len * sizeof(WCHAR) );
memcpy( &buffer[path_len], name, name_len * sizeof(WCHAR) );
buffer[req_len] = 0;
if (lastpart) *lastpart = buffer + path_len;
ret = req_len;
}
else
ret = req_len + 1;
HeapFree( GetProcessHeap(), 0, dll_path );
HeapFree( GetProcessHeap(), 0, search );
}
else
{
if ((dll_path = MODULE_get_dll_load_path( NULL )))
{
ret = RtlDosSearchPath_U( dll_path, name, NULL, buflen * sizeof(WCHAR),
buffer, lastpart ) / sizeof(WCHAR);
HeapFree( GetProcessHeap(), 0, dll_path );
HeapFree( GetProcessHeap(), 0, search );
}
else
{
@ -818,6 +963,7 @@ DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext, DWORD buflen,
return 0;
}
}
}
if (!ret) SetLastError( ERROR_FILE_NOT_FOUND );
else TRACE( "found %s\n", debugstr_w(buffer) );

View File

@ -1639,6 +1639,7 @@ static HANDLE test_create(const char *file)
static void test_SearchPathA(void)
{
static const CHAR testdepA[] = "testdep.dll";
static const CHAR testdeprelA[] = "./testdep.dll";
static const CHAR kernel32A[] = "kernel32.dll";
static const CHAR fileA[] = "";
CHAR pathA[MAX_PATH], buffA[MAX_PATH], path2A[MAX_PATH];
@ -1691,13 +1692,28 @@ static void test_SearchPathA(void)
/* works when activated */
ret = pSearchPathA(NULL, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
todo_wine
ok(ret && ret == strlen(buffA), "got %d\n", ret);
/* path is redirect for wellknown names too */
ret = pSearchPathA(NULL, "testdep.dll", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(ret && ret == strlen(buffA), "got %d\n", ret);
ret = pSearchPathA(NULL, "testdep", ".dll", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(ret && ret == strlen(buffA), "got %d\n", ret);
ret = pSearchPathA(NULL, "testdep", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(!ret, "got %d\n", ret);
/* name contains path */
ret = pSearchPathA(NULL, testdeprelA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(!ret, "got %d\n", ret);
/* fails with specified path that doesn't contain this file */
ret = pSearchPathA(pathA, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(!ret, "got %d\n", ret);
/* path is redirected for wellknown names too */
ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
ok(ret && ret == strlen(buffA), "got %d\n", ret);
todo_wine
ok(strcmp(buffA, path2A), "got wrong path %s, %s\n", buffA, path2A);
ret = pDeactivateActCtx(0, cookie);
@ -1707,8 +1723,12 @@ todo_wine
static void test_SearchPathW(void)
{
static const WCHAR testdeprelW[] = {'.','/','t','e','s','t','d','e','p','.','d','l','l',0};
static const WCHAR testdepW[] = {'t','e','s','t','d','e','p','.','d','l','l',0};
static const WCHAR testdep1W[] = {'t','e','s','t','d','e','p',0};
static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
static const WCHAR extW[] = {'.','e','x','t',0};
static const WCHAR dllW[] = {'.','d','l','l',0};
static const WCHAR fileW[] = { 0 };
WCHAR pathW[MAX_PATH], buffW[MAX_PATH], path2W[MAX_PATH];
WCHAR *ptrW = NULL;
@ -1728,6 +1748,8 @@ if (0)
pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
}
GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
/* empty filename */
SetLastError(0xdeadbeef);
ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
@ -1757,13 +1779,28 @@ if (0)
/* works when activated */
ret = pSearchPathW(NULL, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
todo_wine
ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
ret = pSearchPathW(NULL, testdepW, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
ret = pSearchPathW(NULL, testdep1W, dllW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
ret = pSearchPathW(NULL, testdep1W, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(!ret, "got %d\n", ret);
/* name contains path */
ret = pSearchPathW(NULL, testdeprelW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(!ret, "got %d\n", ret);
/* fails with specified path that doesn't contain this file */
ret = pSearchPathW(pathW, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(!ret, "got %d\n", ret);
/* path is redirect for wellknown names too */
ret = pSearchPathW(NULL, kernel32W, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
todo_wine
ok(lstrcmpW(buffW, path2W), "got wrong path %s, %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(path2W));
ret = pDeactivateActCtx(0, cookie);