2 * Creation of Wine fake dlls for apps that access the dll file directly.
4 * Copyright 2006, 2011 Alexandre Julliard
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
22 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
40 #define WIN32_NO_STATUS
46 #include "wine/unicode.h"
47 #include "wine/library.h"
48 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
54 static const char fakedll_signature
[] = "Wine placeholder DLL";
56 static const unsigned int file_alignment
= 512;
57 static const unsigned int section_alignment
= 4096;
58 static const unsigned int max_dll_name_len
= 64;
60 static void *file_buffer
;
61 static SIZE_T file_buffer_size
;
62 static unsigned int handled_count
;
63 static unsigned int handled_total
;
64 static char **handled_dlls
;
65 static IRegistrar
*registrar
;
75 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
77 /* contents of the dll sections */
79 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
80 0xc2, 0x0c, 0x00 }; /* ret $12 */
82 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
83 0xc2, 0x04, 0x00 }; /* ret $4 */
85 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
88 /* wrapper for WriteFile */
89 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
93 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
94 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
98 /* add a new section to the dll NT header */
99 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
101 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
103 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
104 memcpy( sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
105 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
106 sec
->VirtualAddress
= info
->mem_pos
;
107 sec
->SizeOfRawData
= size
;
108 sec
->PointerToRawData
= info
->file_pos
;
109 sec
->Characteristics
= flags
;
110 info
->file_pos
+= ALIGN( size
, file_alignment
);
111 info
->mem_pos
+= ALIGN( size
, section_alignment
);
112 info
->nt
->FileHeader
.NumberOfSections
++;
115 /* add a data directory to the dll NT header */
116 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
118 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
119 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
122 /* convert a dll name W->A without depending on the current codepage */
123 static char *dll_name_WtoA( char *nameA
, const WCHAR
*nameW
, unsigned int len
)
127 for (i
= 0; i
< len
; i
++)
130 if (nameW
[i
] > 127) return NULL
;
131 if (c
>= 'A' && c
<= 'Z') c
+= 'a' - 'A';
138 /* convert a dll name A->W without depending on the current codepage */
139 static WCHAR
*dll_name_AtoW( WCHAR
*nameW
, const char *nameA
, unsigned int len
)
143 for (i
= 0; i
< len
; i
++) nameW
[i
] = nameA
[i
];
148 /* add a dll to the list of dll that have been taken care of */
149 static BOOL
add_handled_dll( const WCHAR
*name
)
151 unsigned int len
= strlenW( name
);
152 int i
, min
, max
, pos
, res
;
155 if (!(nameA
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 ))) return FALSE
;
156 if (!dll_name_WtoA( nameA
, name
, len
)) goto failed
;
159 max
= handled_count
- 1;
162 pos
= (min
+ max
) / 2;
163 res
= strcmp( handled_dlls
[pos
], nameA
);
164 if (!res
) goto failed
; /* already in the list */
165 if (res
< 0) min
= pos
+ 1;
169 if (handled_count
>= handled_total
)
172 unsigned int new_count
= max( 64, handled_total
* 2 );
174 if (handled_dlls
) new_dlls
= HeapReAlloc( GetProcessHeap(), 0, handled_dlls
,
175 new_count
* sizeof(*handled_dlls
) );
176 else new_dlls
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*handled_dlls
) );
177 if (!new_dlls
) goto failed
;
178 handled_dlls
= new_dlls
;
179 handled_total
= new_count
;
182 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
183 handled_dlls
[i
] = nameA
;
188 HeapFree( GetProcessHeap(), 0, nameA
);
192 /* read in the contents of a file into the global file buffer */
193 /* return 1 on success, 0 on nonexistent file, -1 on other error */
194 static int read_file( const char *name
, void **data
, SIZE_T
*size
)
199 IMAGE_DOS_HEADER
*dos
;
200 IMAGE_NT_HEADERS
*nt
;
201 const size_t min_size
= sizeof(*dos
) + sizeof(fakedll_signature
) +
202 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
204 if ((fd
= open( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
205 if (fstat( fd
, &st
) == -1) goto done
;
207 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
209 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
211 file_buffer_size
= st
.st_size
;
212 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
213 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
216 /* check for valid fake dll file */
218 if (st
.st_size
< min_size
) goto done
;
219 header_size
= min( st
.st_size
, 4096 );
220 if (pread( fd
, file_buffer
, header_size
, 0 ) != header_size
) goto done
;
222 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
223 if (dos
->e_lfanew
< sizeof(fakedll_signature
)) goto done
;
224 if (memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) )) goto done
;
225 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
227 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
228 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
230 /* wrong 32/64 type, pretend it doesn't exist */
234 if (st
.st_size
== header_size
||
235 pread( fd
, (char *)file_buffer
+ header_size
,
236 st
.st_size
- header_size
, header_size
) == st
.st_size
- header_size
)
246 /* build a complete fake dll from scratch */
247 static BOOL
build_fake_dll( HANDLE file
, const WCHAR
*name
)
249 static const WCHAR dotexeW
[] = { '.','e','x','e',0 };
250 IMAGE_DOS_HEADER
*dos
;
251 IMAGE_NT_HEADERS
*nt
;
252 struct dll_info info
;
256 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
257 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
260 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
262 dos
= (IMAGE_DOS_HEADER
*)buffer
;
263 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
264 dos
->e_cblp
= sizeof(*dos
);
266 dos
->e_cparhdr
= lfanew
/ 16;
268 dos
->e_maxalloc
= 0xffff;
271 dos
->e_lfarlc
= lfanew
;
272 dos
->e_lfanew
= lfanew
;
273 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
275 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
276 /* some fields are copied from the source dll */
277 #if defined __x86_64__
278 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
279 #elif defined __aarch64__
280 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARM64
;
281 #elif defined __arm__
282 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARMNT
;
283 #elif defined __powerpc__
284 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_POWERPC
;
286 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
288 nt
->FileHeader
.TimeDateStamp
= 0;
289 nt
->FileHeader
.Characteristics
= 0;
290 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
291 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
292 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
293 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
294 nt
->OptionalHeader
.MajorImageVersion
= 1;
295 nt
->OptionalHeader
.MinorImageVersion
= 0;
296 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
297 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
298 nt
->OptionalHeader
.Win32VersionValue
= 0;
299 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
300 nt
->OptionalHeader
.DllCharacteristics
= 0;
301 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
302 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
303 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
304 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
305 /* other fields have fixed values */
306 nt
->Signature
= IMAGE_NT_SIGNATURE
;
307 nt
->FileHeader
.NumberOfSections
= 0;
308 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
309 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
310 nt
->OptionalHeader
.ImageBase
= 0x10000000;
311 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
312 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
313 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
315 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
316 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
317 info
.file_pos
= ALIGN( header_size
, file_alignment
);
319 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
320 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
322 ext
= strrchrW( name
, '.' );
323 if (!ext
|| strcmpiW( ext
, dotexeW
)) nt
->FileHeader
.Characteristics
|= IMAGE_FILE_DLL
;
325 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
327 size
= sizeof(dll_code_section
);
328 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
332 size
= sizeof(exe_code_section
);
333 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
335 nt
->OptionalHeader
.SizeOfCode
= size
;
336 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
338 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
339 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
340 add_section( &info
, ".reloc", sizeof(reloc_section
),
341 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
343 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
344 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
345 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
346 ret
= xwrite( &info
, buffer
, header_size
, 0 );
348 HeapFree( GetProcessHeap(), 0, buffer
);
352 /* check if an existing file is a fake dll so that we can overwrite it */
353 static BOOL
is_fake_dll( HANDLE h
)
355 IMAGE_DOS_HEADER
*dos
;
357 BYTE buffer
[sizeof(*dos
) + sizeof(fakedll_signature
)];
359 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
361 dos
= (IMAGE_DOS_HEADER
*)buffer
;
362 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
363 if (dos
->e_lfanew
< size
) return FALSE
;
364 return !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
367 /* create directories leading to a given file */
368 static void create_directories( const WCHAR
*name
)
372 /* create the directory/directories */
373 path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1)*sizeof(WCHAR
));
376 p
= strchrW(path
, '\\');
380 if (!CreateDirectoryW(path
, NULL
))
381 TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path
), GetLastError());
383 p
= strchrW(p
+1, '\\');
385 HeapFree(GetProcessHeap(), 0, path
);
388 static inline char *prepend( char *buffer
, const char *str
, size_t len
)
390 return memcpy( buffer
- len
, str
, len
);
393 /* try to load a pre-compiled fake dll */
394 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
396 const char *build_dir
= wine_get_build_dir();
400 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
404 if ((p
= strrchrW( name
, '\\' ))) name
= p
+ 1;
407 len
= strlenW( name
);
408 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/") + len
;
409 while ((path
= wine_dll_enum_load_path( i
++ ))) maxlen
= max( maxlen
, strlen(path
) );
410 maxlen
+= sizeof("/fakedlls") + len
+ sizeof(".fake");
412 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return NULL
;
414 pos
= maxlen
- len
- sizeof(".fake");
415 if (!dll_name_WtoA( file
+ pos
, name
, len
)) goto done
;
420 strcpy( file
+ pos
+ len
+ 1, ".fake" );
425 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".dll", 4 )) namelen
-= 4;
426 ptr
= prepend( ptr
, ptr
, namelen
);
427 ptr
= prepend( ptr
, "/dlls", sizeof("/dlls") - 1 );
428 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
429 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
431 /* now as a program */
434 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".exe", 4 )) namelen
-= 4;
435 ptr
= prepend( ptr
, ptr
, namelen
);
436 ptr
= prepend( ptr
, "/programs", sizeof("/programs") - 1 );
437 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
438 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
441 file
[pos
+ len
+ 1] = 0;
442 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
444 ptr
= prepend( file
+ pos
, "/fakedlls", sizeof("/fakedlls") - 1 );
445 ptr
= prepend( ptr
, path
, strlen(path
) );
446 if ((res
= read_file( ptr
, &data
, size
))) break;
450 HeapFree( GetProcessHeap(), 0, file
);
451 if (res
== 1) return data
;
455 /* create the fake dll destination file */
456 static HANDLE
create_dest_file( const WCHAR
*name
)
458 /* first check for an existing file */
459 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
460 if (h
!= INVALID_HANDLE_VALUE
)
462 if (!is_fake_dll( h
))
464 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
468 /* truncate the file */
469 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
474 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
476 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
477 if (h
== INVALID_HANDLE_VALUE
)
478 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
483 /* XML parsing code copied from ntdll */
497 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
499 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
502 static inline BOOL
isxmlspace( char ch
)
504 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
507 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
513 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
516 xmlbuf
->ptr
= xmlbuf
->end
;
520 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
522 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
523 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
525 if (ptr
+ 3 > xmlbuf
->end
)
527 xmlbuf
->ptr
= xmlbuf
->end
;
530 xmlbuf
->ptr
= ptr
+ 3;
536 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
539 elem
->ptr
= xmlbuf
->ptr
;
540 elem
->len
= ptr
- xmlbuf
->ptr
;
542 return xmlbuf
->ptr
!= xmlbuf
->end
;
545 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
,
546 BOOL
* error
, BOOL
* end
)
552 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
555 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
557 if (*xmlbuf
->ptr
== '/')
560 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
569 if (*xmlbuf
->ptr
== '>')
577 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
579 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
581 name
->ptr
= xmlbuf
->ptr
;
582 name
->len
= ptr
-xmlbuf
->ptr
;
586 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
589 if (ptr
== xmlbuf
->end
) return FALSE
;
591 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
594 xmlbuf
->ptr
= xmlbuf
->end
;
598 value
->len
= ptr
- value
->ptr
;
599 xmlbuf
->ptr
= ptr
+ 1;
601 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
607 static void get_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
608 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
610 static const WCHAR trailerW
[] = {'_','d','e','a','d','b','e','e','f',0};
613 pos
= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
, size
);
615 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
617 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
619 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
621 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
622 memcpy( buffer
+ pos
, trailerW
, sizeof(trailerW
) );
626 static BOOL
create_winsxs_dll( const WCHAR
*dll_name
, const xmlstr_t
*arch
, const xmlstr_t
*name
,
627 const xmlstr_t
*key
, const xmlstr_t
*version
, const xmlstr_t
*lang
,
628 const void *dll_data
, size_t dll_size
)
630 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\'};
632 const WCHAR
*filename
;
633 DWORD pos
, written
, path_len
;
637 if (!(filename
= strrchrW( dll_name
, '\\' ))) filename
= dll_name
;
640 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
641 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + strlenW( filename
) + 1;
643 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
644 pos
= GetWindowsDirectoryW( path
, path_len
);
646 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
647 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
648 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, path_len
- pos
);
649 pos
+= strlenW( path
+ pos
);
651 strcpyW( path
+ pos
, filename
);
652 handle
= create_dest_file( path
);
653 if (handle
&& handle
!= INVALID_HANDLE_VALUE
)
655 TRACE( "creating %s\n", debugstr_w(path
) );
656 ret
= (WriteFile( handle
, dll_data
, dll_size
, &written
, NULL
) && written
== dll_size
);
657 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
658 CloseHandle( handle
);
659 if (!ret
) DeleteFileW( path
);
661 HeapFree( GetProcessHeap(), 0, path
);
665 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
666 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
668 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s','\\'};
669 static const WCHAR extensionW
[] = {'.','m','a','n','i','f','e','s','t',0};
671 DWORD pos
, written
, path_len
;
675 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
676 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + sizeof(extensionW
)/sizeof(WCHAR
);
678 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
679 pos
= GetWindowsDirectoryW( path
, MAX_PATH
);
681 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
682 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
683 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, MAX_PATH
- pos
);
684 strcatW( path
+ pos
, extensionW
);
685 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
686 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
688 create_directories( path
);
689 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
692 if (handle
!= INVALID_HANDLE_VALUE
)
694 TRACE( "creating %s\n", debugstr_w(path
) );
695 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
696 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
697 CloseHandle( handle
);
698 if (!ret
) DeleteFileW( path
);
700 HeapFree( GetProcessHeap(), 0, path
);
710 static BOOL CALLBACK
register_manifest( HMODULE module
, const WCHAR
*type
, WCHAR
*res_name
, LONG_PTR arg
)
713 static const char current_arch
[] = "x86";
714 #elif defined __x86_64__
715 static const char current_arch
[] = "amd64";
717 static const char current_arch
[] = "none";
719 static const WCHAR manifestW
[] = {'W','I','N','E','_','M','A','N','I','F','E','S','T'};
720 const struct dll_data
*dll_data
= (const struct dll_data
*)arg
;
722 xmlstr_t elem
, attr_name
, attr_value
;
723 xmlstr_t name
, version
, arch
, key
, lang
;
724 BOOL end
= FALSE
, error
;
725 const char *manifest
;
729 if (IS_INTRESOURCE(res_name
) || strncmpW( res_name
, manifestW
, sizeof(manifestW
)/sizeof(WCHAR
) ))
732 rsrc
= FindResourceW( module
, res_name
, type
);
733 manifest
= LoadResource( module
, rsrc
);
734 len
= SizeofResource( module
, rsrc
);
736 buffer
.ptr
= manifest
;
737 buffer
.end
= manifest
+ len
;
738 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
739 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
741 while (next_xml_elem( &buffer
, &elem
))
743 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
744 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
, &end
))
746 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
747 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
748 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
749 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
750 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
752 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
757 lang
.len
= strlen( lang
.ptr
);
759 if (!arch
.len
) /* fixup the architecture */
761 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
762 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
763 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
764 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
765 arch
.ptr
= current_arch
;
766 arch
.len
= strlen( current_arch
);
767 if (create_winsxs_dll( dll_data
->name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
->data
, dll_data
->size
))
768 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
769 HeapFree( GetProcessHeap(), 0, new_buffer
);
773 if (create_winsxs_dll( dll_data
->name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
->data
, dll_data
->size
))
774 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
782 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
784 HRESULT
*hr
= (HRESULT
*)arg
;
786 HRSRC rsrc
= FindResourceW( module
, name
, type
);
787 char *str
= LoadResource( module
, rsrc
);
788 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
790 if (!str
) return FALSE
;
791 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
792 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
793 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
794 buffer
[lenW
- 1] = 0;
795 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
796 HeapFree( GetProcessHeap(), 0, buffer
);
800 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
)
802 static const WCHAR atlW
[] = {'a','t','l','1','0','0','.','d','l','l',0};
803 static const WCHAR moduleW
[] = {'M','O','D','U','L','E',0};
804 static const WCHAR regtypeW
[] = {'W','I','N','E','_','R','E','G','I','S','T','R','Y',0};
805 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
806 LDR_RESOURCE_INFO info
;
808 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
809 struct dll_data dll_data
= { name
, data
, size
};
811 EnumResourceNamesW( module
, (WCHAR
*)RT_MANIFEST
, register_manifest
, (LONG_PTR
)&dll_data
);
813 info
.Type
= (ULONG_PTR
)regtypeW
;
814 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
818 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
819 HMODULE atl
= LoadLibraryW( atlW
);
821 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
822 hr
= pAtlCreateRegistrar( ®istrar
);
828 ERR( "failed to create IRegistrar: %x\n", hr
);
833 TRACE( "registering %s\n", debugstr_w(name
) );
834 IRegistrar_ClearReplacements( registrar
);
835 IRegistrar_AddReplacement( registrar
, moduleW
, name
);
836 EnumResourceNamesW( module
, regtypeW
, register_resource
, (LONG_PTR
)&hr
);
837 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
840 /* copy a fake dll file to the dest directory */
841 static void install_fake_dll( WCHAR
*dest
, char *file
, const char *ext
)
847 WCHAR
*destname
= dest
+ strlenW(dest
);
848 char *name
= strrchr( file
, '/' ) + 1;
849 char *end
= name
+ strlen(name
);
851 if (ext
) strcpy( end
, ext
);
852 if (!(ret
= read_file( file
, &data
, &size
))) return;
854 if (end
> name
+ 2 && !strncmp( end
- 2, "16", 2 )) end
-= 2; /* remove "16" suffix */
855 dll_name_AtoW( destname
, name
, end
- name
);
856 if (!add_handled_dll( destname
)) ret
= -1;
860 HANDLE h
= create_dest_file( dest
);
862 if (h
&& h
!= INVALID_HANDLE_VALUE
)
864 TRACE( "%s -> %s\n", debugstr_a(file
), debugstr_w(dest
) );
866 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
867 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
869 if (ret
) register_fake_dll( dest
, data
, size
);
870 else DeleteFileW( dest
);
873 *destname
= 0; /* restore it for next file */
876 /* find and install all fake dlls in a given lib directory */
877 static void install_lib_dir( WCHAR
*dest
, char *file
, const char *default_ext
)
883 if (!(dir
= opendir( file
))) return;
884 name
= file
+ strlen(file
);
886 while ((de
= readdir( dir
)))
888 if (strlen( de
->d_name
) > max_dll_name_len
) continue;
889 if (!strcmp( de
->d_name
, "." )) continue;
890 if (!strcmp( de
->d_name
, ".." )) continue;
891 strcpy( name
, de
->d_name
);
892 if (default_ext
) /* inside build dir */
895 strcat( name
, de
->d_name
);
896 if (!strchr( de
->d_name
, '.' )) strcat( name
, default_ext
);
897 install_fake_dll( dest
, file
, ".fake" );
899 else install_fake_dll( dest
, file
, NULL
);
904 /* create fake dlls in dirname for all the files we can find */
905 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
)
907 const char *build_dir
= wine_get_build_dir();
909 unsigned int i
, maxlen
= 0;
913 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/");
914 for (i
= 0; (path
= wine_dll_enum_load_path(i
)); i
++) maxlen
= max( maxlen
, strlen(path
) );
915 maxlen
+= 2 * max_dll_name_len
+ 2 + sizeof(".dll.fake");
916 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return FALSE
;
918 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (strlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
920 HeapFree( GetProcessHeap(), 0, file
);
923 strcpyW( dest
, dirname
);
924 dest
[strlenW(dest
) - 1] = 0; /* remove wildcard */
928 strcpy( file
, build_dir
);
929 strcat( file
, "/dlls" );
930 install_lib_dir( dest
, file
, ".dll" );
931 strcpy( file
, build_dir
);
932 strcat( file
, "/programs" );
933 install_lib_dir( dest
, file
, ".exe" );
935 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
937 strcpy( file
, path
);
938 strcat( file
, "/fakedlls" );
939 install_lib_dir( dest
, file
, NULL
);
941 HeapFree( GetProcessHeap(), 0, file
);
942 HeapFree( GetProcessHeap(), 0, dest
);
946 /***********************************************************************
949 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
954 const WCHAR
*filename
;
957 if (!(filename
= strrchrW( name
, '\\' ))) filename
= name
;
960 /* check for empty name which means to only create the directory */
963 create_directories( name
);
966 if (filename
[0] == '*' && !filename
[1]) return create_wildcard_dlls( name
);
968 add_handled_dll( filename
);
970 if (!(h
= create_dest_file( name
))) return TRUE
; /* not a fake dll */
971 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
973 if (source
[0] == '-' && !source
[1])
975 /* '-' source means delete the file */
976 TRACE( "deleting %s\n", debugstr_w(name
) );
979 else if ((buffer
= load_fake_dll( source
, &size
)))
983 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
984 if (ret
) register_fake_dll( name
, buffer
, size
);
985 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
989 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
990 ret
= build_fake_dll( h
, name
);
994 if (!ret
) DeleteFileW( name
);
999 /***********************************************************************
1002 void cleanup_fake_dlls(void)
1004 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
1006 HeapFree( GetProcessHeap(), 0, handled_dlls
);
1007 handled_dlls
= NULL
;
1008 handled_count
= handled_total
= 0;
1009 if (registrar
) IRegistrar_Release( registrar
);