mirror of
https://github.com/reactos/wine.git
synced 2024-11-25 04:39:45 +00:00
setupapi: Add support for creating WinSxS manifest files from fake dll resources.
This commit is contained in:
parent
0decc777eb
commit
e8a7246e8b
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Creation of Wine fake dlls for apps that access the dll file directly.
|
||||
*
|
||||
* Copyright 2006 Alexandre Julliard
|
||||
* Copyright 2006, 2011 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -470,6 +470,278 @@ static HANDLE create_dest_file( const WCHAR *name )
|
||||
return h;
|
||||
}
|
||||
|
||||
/* XML parsing code copied from ntdll */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *ptr;
|
||||
unsigned int len;
|
||||
} xmlstr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *ptr;
|
||||
const char *end;
|
||||
} xmlbuf_t;
|
||||
|
||||
static inline BOOL xmlstr_cmp(const xmlstr_t* xmlstr, const char *str)
|
||||
{
|
||||
return !strncmp(xmlstr->ptr, str, xmlstr->len) && !str[xmlstr->len];
|
||||
}
|
||||
|
||||
static inline BOOL isxmlspace( char ch )
|
||||
{
|
||||
return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
|
||||
}
|
||||
|
||||
static BOOL next_xml_elem( xmlbuf_t *xmlbuf, xmlstr_t *elem )
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ptr = memchr(xmlbuf->ptr, '<', xmlbuf->end - xmlbuf->ptr);
|
||||
if (!ptr)
|
||||
{
|
||||
xmlbuf->ptr = xmlbuf->end;
|
||||
return FALSE;
|
||||
}
|
||||
ptr++;
|
||||
if (ptr + 3 < xmlbuf->end && ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') /* skip comment */
|
||||
{
|
||||
for (ptr += 3; ptr + 3 <= xmlbuf->end; ptr++)
|
||||
if (ptr[0] == '-' && ptr[1] == '-' && ptr[2] == '>') break;
|
||||
|
||||
if (ptr + 3 > xmlbuf->end)
|
||||
{
|
||||
xmlbuf->ptr = xmlbuf->end;
|
||||
return FALSE;
|
||||
}
|
||||
xmlbuf->ptr = ptr + 3;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
xmlbuf->ptr = ptr;
|
||||
while (ptr < xmlbuf->end && !isxmlspace(*ptr) && *ptr != '>' && (*ptr != '/' || ptr == xmlbuf->ptr))
|
||||
ptr++;
|
||||
|
||||
elem->ptr = xmlbuf->ptr;
|
||||
elem->len = ptr - xmlbuf->ptr;
|
||||
xmlbuf->ptr = ptr;
|
||||
return xmlbuf->ptr != xmlbuf->end;
|
||||
}
|
||||
|
||||
static BOOL next_xml_attr(xmlbuf_t* xmlbuf, xmlstr_t* name, xmlstr_t* value,
|
||||
BOOL* error, BOOL* end)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
*error = TRUE;
|
||||
|
||||
while (xmlbuf->ptr < xmlbuf->end && isxmlspace(*xmlbuf->ptr))
|
||||
xmlbuf->ptr++;
|
||||
|
||||
if (xmlbuf->ptr == xmlbuf->end) return FALSE;
|
||||
|
||||
if (*xmlbuf->ptr == '/')
|
||||
{
|
||||
xmlbuf->ptr++;
|
||||
if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
|
||||
return FALSE;
|
||||
|
||||
xmlbuf->ptr++;
|
||||
*end = TRUE;
|
||||
*error = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*xmlbuf->ptr == '>')
|
||||
{
|
||||
xmlbuf->ptr++;
|
||||
*error = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ptr = xmlbuf->ptr;
|
||||
while (ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isxmlspace(*ptr)) ptr++;
|
||||
|
||||
if (ptr == xmlbuf->end || *ptr != '=') return FALSE;
|
||||
|
||||
name->ptr = xmlbuf->ptr;
|
||||
name->len = ptr-xmlbuf->ptr;
|
||||
xmlbuf->ptr = ptr;
|
||||
|
||||
ptr++;
|
||||
if (ptr == xmlbuf->end || (*ptr != '"' && *ptr != '\'')) return FALSE;
|
||||
|
||||
value->ptr = ++ptr;
|
||||
if (ptr == xmlbuf->end) return FALSE;
|
||||
|
||||
ptr = memchr(ptr, ptr[-1], xmlbuf->end - ptr);
|
||||
if (!ptr)
|
||||
{
|
||||
xmlbuf->ptr = xmlbuf->end;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
value->len = ptr - value->ptr;
|
||||
xmlbuf->ptr = ptr + 1;
|
||||
|
||||
if (xmlbuf->ptr == xmlbuf->end) return FALSE;
|
||||
|
||||
*error = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void get_manifest_filename( const xmlstr_t *arch, const xmlstr_t *name, const xmlstr_t *key,
|
||||
const xmlstr_t *version, WCHAR *buffer, DWORD size )
|
||||
{
|
||||
static const WCHAR trailerW[] = {'_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
|
||||
DWORD pos;
|
||||
|
||||
pos = MultiByteToWideChar( CP_UTF8, 0, arch->ptr, arch->len, buffer, size );
|
||||
buffer[pos++] = '_';
|
||||
pos += MultiByteToWideChar( CP_UTF8, 0, name->ptr, name->len, buffer + pos, size - pos );
|
||||
buffer[pos++] = '_';
|
||||
pos += MultiByteToWideChar( CP_UTF8, 0, key->ptr, key->len, buffer + pos, size - pos );
|
||||
buffer[pos++] = '_';
|
||||
pos += MultiByteToWideChar( CP_UTF8, 0, version->ptr, version->len, buffer + pos, size - pos );
|
||||
memcpy( buffer + pos, trailerW, sizeof(trailerW) );
|
||||
strlwrW( buffer );
|
||||
}
|
||||
|
||||
static BOOL create_winsxs_dll( const WCHAR *dll_name, const xmlstr_t *arch, const xmlstr_t *name,
|
||||
const xmlstr_t *key, const xmlstr_t *version,
|
||||
const void *dll_data, size_t dll_size )
|
||||
{
|
||||
static const WCHAR winsxsW[] = {'w','i','n','s','x','s','\\'};
|
||||
WCHAR *path;
|
||||
const WCHAR *filename;
|
||||
DWORD pos, written, path_len;
|
||||
HANDLE handle;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!(filename = strrchrW( dll_name, '\\' ))) filename = dll_name;
|
||||
else filename++;
|
||||
|
||||
path_len = GetWindowsDirectoryW( NULL, 0 ) + 1 + sizeof(winsxsW)/sizeof(WCHAR)
|
||||
+ arch->len + name->len + key->len + version->len + 18 + strlenW( filename ) + 1;
|
||||
|
||||
path = HeapAlloc( GetProcessHeap(), 0, path_len * sizeof(WCHAR) );
|
||||
pos = GetWindowsDirectoryW( path, path_len );
|
||||
path[pos++] = '\\';
|
||||
memcpy( path + pos, winsxsW, sizeof(winsxsW) );
|
||||
pos += sizeof(winsxsW) / sizeof(WCHAR);
|
||||
get_manifest_filename( arch, name, key, version, path + pos, path_len - pos );
|
||||
pos += strlenW( path + pos );
|
||||
path[pos++] = '\\';
|
||||
strcpyW( path + pos, filename );
|
||||
handle = create_dest_file( path );
|
||||
if (handle && handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
TRACE( "creating %s\n", debugstr_w(path) );
|
||||
ret = (WriteFile( handle, dll_data, dll_size, &written, NULL ) && written == dll_size);
|
||||
if (!ret) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path), GetLastError() );
|
||||
CloseHandle( handle );
|
||||
if (!ret) DeleteFileW( path );
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, path );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL create_manifest( const xmlstr_t *arch, const xmlstr_t *name, const xmlstr_t *key,
|
||||
const xmlstr_t *version, const void *data, DWORD len )
|
||||
{
|
||||
static const WCHAR winsxsW[] = {'w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s','\\'};
|
||||
static const WCHAR extensionW[] = {'.','m','a','n','i','f','e','s','t',0};
|
||||
WCHAR *path;
|
||||
DWORD pos, written, path_len;
|
||||
HANDLE handle;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
path_len = GetWindowsDirectoryW( NULL, 0 ) + 1 + sizeof(winsxsW)/sizeof(WCHAR)
|
||||
+ arch->len + name->len + key->len + version->len + 18 + sizeof(extensionW)/sizeof(WCHAR);
|
||||
|
||||
path = HeapAlloc( GetProcessHeap(), 0, path_len * sizeof(WCHAR) );
|
||||
pos = GetWindowsDirectoryW( path, MAX_PATH );
|
||||
path[pos++] = '\\';
|
||||
memcpy( path + pos, winsxsW, sizeof(winsxsW) );
|
||||
pos += sizeof(winsxsW) / sizeof(WCHAR);
|
||||
get_manifest_filename( arch, name, key, version, path + pos, MAX_PATH - pos );
|
||||
strcatW( path + pos, extensionW );
|
||||
handle = CreateFileW( path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
|
||||
if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
create_directories( path );
|
||||
handle = CreateFileW( path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
|
||||
}
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
TRACE( "creating %s\n", debugstr_w(path) );
|
||||
ret = (WriteFile( handle, data, len, &written, NULL ) && written == len);
|
||||
if (!ret) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path), GetLastError() );
|
||||
CloseHandle( handle );
|
||||
if (!ret) DeleteFileW( path );
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, path );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void register_manifest( const WCHAR *dll_name, const char *manifest, DWORD len,
|
||||
const void *dll_data, size_t dll_size )
|
||||
{
|
||||
#ifdef __i386__
|
||||
static const char current_arch[] = "x86";
|
||||
#elif defined __x86_64__
|
||||
static const char current_arch[] = "amd64";
|
||||
#else
|
||||
static const char current_arch[] = "none";
|
||||
#endif
|
||||
xmlbuf_t buffer;
|
||||
xmlstr_t elem, attr_name, attr_value;
|
||||
xmlstr_t name, version, arch, key;
|
||||
BOOL end = FALSE, error;
|
||||
|
||||
buffer.ptr = manifest;
|
||||
buffer.end = manifest + len;
|
||||
name.ptr = version.ptr = arch.ptr = key.ptr = NULL;
|
||||
name.len = version.len = arch.len = key.len = 0;
|
||||
|
||||
while (next_xml_elem( &buffer, &elem ))
|
||||
{
|
||||
if (!xmlstr_cmp( &elem, "assemblyIdentity" )) continue;
|
||||
while (next_xml_attr( &buffer, &attr_name, &attr_value, &error, &end ))
|
||||
{
|
||||
if (xmlstr_cmp(&attr_name, "name")) name = attr_value;
|
||||
else if (xmlstr_cmp(&attr_name, "version")) version = attr_value;
|
||||
else if (xmlstr_cmp(&attr_name, "processorArchitecture")) arch = attr_value;
|
||||
else if (xmlstr_cmp(&attr_name, "publicKeyToken")) key = attr_value;
|
||||
}
|
||||
if (!error && name.ptr && version.ptr && arch.ptr && key.ptr)
|
||||
{
|
||||
if (!arch.len) /* fixup the architecture */
|
||||
{
|
||||
char *new_buffer = HeapAlloc( GetProcessHeap(), 0, len + sizeof(current_arch) );
|
||||
memcpy( new_buffer, manifest, arch.ptr - manifest );
|
||||
strcpy( new_buffer + (arch.ptr - manifest), current_arch );
|
||||
memcpy( new_buffer + strlen(new_buffer), arch.ptr, len - (arch.ptr - manifest) );
|
||||
arch.ptr = current_arch;
|
||||
arch.len = strlen( current_arch );
|
||||
if (create_winsxs_dll( dll_name, &arch, &name, &key, &version, dll_data, dll_size ))
|
||||
create_manifest( &arch, &name, &key, &version, new_buffer, len + arch.len );
|
||||
HeapFree( GetProcessHeap(), 0, new_buffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (create_winsxs_dll( dll_name, &arch, &name, &key, &version, dll_data, dll_size ))
|
||||
create_manifest( &arch, &name, &key, &version, manifest, len );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL CALLBACK register_resource( HMODULE module, LPCWSTR type, LPWSTR name, LONG_PTR arg )
|
||||
{
|
||||
HRESULT *hr = (HRESULT *)arg;
|
||||
@ -493,10 +765,18 @@ static void register_fake_dll( const WCHAR *name, const void *data, size_t size
|
||||
static const WCHAR atlW[] = {'a','t','l','.','d','l','l',0};
|
||||
static const WCHAR moduleW[] = {'M','O','D','U','L','E',0};
|
||||
static const WCHAR regtypeW[] = {'W','I','N','E','_','R','E','G','I','S','T','R','Y',0};
|
||||
static const WCHAR manifestW[] = {'W','I','N','E','_','M','A','N','I','F','E','S','T',0};
|
||||
const IMAGE_RESOURCE_DIRECTORY *resdir;
|
||||
LDR_RESOURCE_INFO info;
|
||||
HRESULT hr = S_OK;
|
||||
HMODULE module = (HMODULE)((ULONG_PTR)data | 1);
|
||||
HRSRC rsrc;
|
||||
|
||||
if ((rsrc = FindResourceW( module, manifestW, MAKEINTRESOURCEW(RT_MANIFEST) )))
|
||||
{
|
||||
char *manifest = LoadResource( module, rsrc );
|
||||
register_manifest( name, manifest, SizeofResource( module, rsrc ), data, size );
|
||||
}
|
||||
|
||||
info.Type = (ULONG_PTR)regtypeW;
|
||||
if (LdrFindResourceDirectory_U( module, &info, 1, &resdir )) return;
|
||||
|
Loading…
Reference in New Issue
Block a user