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>
38 #define NONAMELESSSTRUCT
39 #define NONAMELESSUNION
41 #define WIN32_NO_STATUS
47 #include "wine/unicode.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
55 static const char fakedll_signature
[] = "Wine placeholder DLL";
57 static const unsigned int file_alignment
= 512;
58 static const unsigned int section_alignment
= 4096;
59 static const unsigned int max_dll_name_len
= 64;
61 static void *file_buffer
;
62 static SIZE_T file_buffer_size
;
63 static unsigned int handled_count
;
64 static unsigned int handled_total
;
65 static char **handled_dlls
;
66 static IRegistrar
*registrar
;
76 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
78 /* contents of the dll sections */
80 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
81 0xc2, 0x0c, 0x00 }; /* ret $12 */
83 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
84 0xc2, 0x04, 0x00 }; /* ret $4 */
86 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
89 /* wrapper for WriteFile */
90 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
94 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
95 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
99 /* add a new section to the dll NT header */
100 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
102 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
104 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
105 memcpy( sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
106 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
107 sec
->VirtualAddress
= info
->mem_pos
;
108 sec
->SizeOfRawData
= size
;
109 sec
->PointerToRawData
= info
->file_pos
;
110 sec
->Characteristics
= flags
;
111 info
->file_pos
+= ALIGN( size
, file_alignment
);
112 info
->mem_pos
+= ALIGN( size
, section_alignment
);
113 info
->nt
->FileHeader
.NumberOfSections
++;
116 /* add a data directory to the dll NT header */
117 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
119 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
120 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
123 /* convert a dll name W->A without depending on the current codepage */
124 static char *dll_name_WtoA( char *nameA
, const WCHAR
*nameW
, unsigned int len
)
128 for (i
= 0; i
< len
; i
++)
131 if (nameW
[i
] > 127) return NULL
;
132 if (c
>= 'A' && c
<= 'Z') c
+= 'a' - 'A';
139 /* convert a dll name A->W without depending on the current codepage */
140 static WCHAR
*dll_name_AtoW( WCHAR
*nameW
, const char *nameA
, unsigned int len
)
144 for (i
= 0; i
< len
; i
++) nameW
[i
] = nameA
[i
];
149 /* add a dll to the list of dll that have been taken care of */
150 static BOOL
add_handled_dll( const WCHAR
*name
)
152 unsigned int len
= strlenW( name
);
153 int i
, min
, max
, pos
, res
;
156 if (!(nameA
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 ))) return FALSE
;
157 if (!dll_name_WtoA( nameA
, name
, len
)) goto failed
;
160 max
= handled_count
- 1;
163 pos
= (min
+ max
) / 2;
164 res
= strcmp( handled_dlls
[pos
], nameA
);
165 if (!res
) goto failed
; /* already in the list */
166 if (res
< 0) min
= pos
+ 1;
170 if (handled_count
>= handled_total
)
173 unsigned int new_count
= max( 64, handled_total
* 2 );
175 if (handled_dlls
) new_dlls
= HeapReAlloc( GetProcessHeap(), 0, handled_dlls
,
176 new_count
* sizeof(*handled_dlls
) );
177 else new_dlls
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*handled_dlls
) );
178 if (!new_dlls
) goto failed
;
179 handled_dlls
= new_dlls
;
180 handled_total
= new_count
;
183 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
184 handled_dlls
[i
] = nameA
;
189 HeapFree( GetProcessHeap(), 0, nameA
);
193 /* read in the contents of a file into the global file buffer */
194 /* return 1 on success, 0 on nonexistent file, -1 on other error */
195 static int read_file( const char *name
, void **data
, SIZE_T
*size
)
200 IMAGE_DOS_HEADER
*dos
;
201 IMAGE_NT_HEADERS
*nt
;
202 const size_t min_size
= sizeof(*dos
) + sizeof(fakedll_signature
) +
203 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
205 if ((fd
= open( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
206 if (fstat( fd
, &st
) == -1) goto done
;
208 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
210 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
212 file_buffer_size
= st
.st_size
;
213 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
214 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
217 /* check for valid fake dll file */
219 if (st
.st_size
< min_size
) goto done
;
220 header_size
= min( st
.st_size
, 4096 );
221 if (pread( fd
, file_buffer
, header_size
, 0 ) != header_size
) goto done
;
223 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
224 if (dos
->e_lfanew
< sizeof(fakedll_signature
)) goto done
;
225 if (memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) )) goto done
;
226 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
228 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
229 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
231 /* wrong 32/64 type, pretend it doesn't exist */
235 if (st
.st_size
== header_size
||
236 pread( fd
, (char *)file_buffer
+ header_size
,
237 st
.st_size
- header_size
, header_size
) == st
.st_size
- header_size
)
247 /* build a complete fake dll from scratch */
248 static BOOL
build_fake_dll( HANDLE file
, const WCHAR
*name
)
250 static const WCHAR dotexeW
[] = { '.','e','x','e',0 };
251 IMAGE_DOS_HEADER
*dos
;
252 IMAGE_NT_HEADERS
*nt
;
253 struct dll_info info
;
257 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
258 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
261 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
263 dos
= (IMAGE_DOS_HEADER
*)buffer
;
264 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
265 dos
->e_cblp
= sizeof(*dos
);
267 dos
->e_cparhdr
= lfanew
/ 16;
269 dos
->e_maxalloc
= 0xffff;
272 dos
->e_lfarlc
= lfanew
;
273 dos
->e_lfanew
= lfanew
;
274 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
276 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
277 /* some fields are copied from the source dll */
278 #if defined __x86_64__
279 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
280 #elif defined __aarch64__
281 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARM64
;
282 #elif defined __arm__
283 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARMNT
;
284 #elif defined __powerpc__
285 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_POWERPC
;
287 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
289 nt
->FileHeader
.TimeDateStamp
= 0;
290 nt
->FileHeader
.Characteristics
= 0;
291 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
292 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
293 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
294 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
295 nt
->OptionalHeader
.MajorImageVersion
= 1;
296 nt
->OptionalHeader
.MinorImageVersion
= 0;
297 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
298 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
299 nt
->OptionalHeader
.Win32VersionValue
= 0;
300 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
301 nt
->OptionalHeader
.DllCharacteristics
= 0;
302 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
303 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
304 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
305 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
306 /* other fields have fixed values */
307 nt
->Signature
= IMAGE_NT_SIGNATURE
;
308 nt
->FileHeader
.NumberOfSections
= 0;
309 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
310 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
311 nt
->OptionalHeader
.ImageBase
= 0x10000000;
312 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
313 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
314 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
316 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
317 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
318 info
.file_pos
= ALIGN( header_size
, file_alignment
);
320 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
321 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
323 ext
= strrchrW( name
, '.' );
324 if (!ext
|| strcmpiW( ext
, dotexeW
)) nt
->FileHeader
.Characteristics
|= IMAGE_FILE_DLL
;
326 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
328 size
= sizeof(dll_code_section
);
329 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
333 size
= sizeof(exe_code_section
);
334 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
336 nt
->OptionalHeader
.SizeOfCode
= size
;
337 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
339 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
340 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
341 add_section( &info
, ".reloc", sizeof(reloc_section
),
342 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
344 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
345 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
346 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
347 ret
= xwrite( &info
, buffer
, header_size
, 0 );
349 HeapFree( GetProcessHeap(), 0, buffer
);
353 /* check if an existing file is a fake dll so that we can overwrite it */
354 static BOOL
is_fake_dll( HANDLE h
)
356 IMAGE_DOS_HEADER
*dos
;
358 BYTE buffer
[sizeof(*dos
) + sizeof(fakedll_signature
)];
360 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
362 dos
= (IMAGE_DOS_HEADER
*)buffer
;
363 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
364 if (dos
->e_lfanew
< size
) return FALSE
;
365 return !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
368 /* create directories leading to a given file */
369 static void create_directories( const WCHAR
*name
)
373 /* create the directory/directories */
374 path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1)*sizeof(WCHAR
));
377 p
= strchrW(path
, '\\');
381 if (!CreateDirectoryW(path
, NULL
))
382 TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path
), GetLastError());
384 p
= strchrW(p
+1, '\\');
386 HeapFree(GetProcessHeap(), 0, path
);
389 static inline char *prepend( char *buffer
, const char *str
, size_t len
)
391 return memcpy( buffer
- len
, str
, len
);
394 /* try to load a pre-compiled fake dll */
395 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
397 const char *build_dir
= wine_get_build_dir();
401 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
405 if ((p
= strrchrW( name
, '\\' ))) name
= p
+ 1;
408 len
= strlenW( name
);
409 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/") + len
;
410 while ((path
= wine_dll_enum_load_path( i
++ ))) maxlen
= max( maxlen
, strlen(path
) );
411 maxlen
+= sizeof("/fakedlls") + len
+ sizeof(".fake");
413 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return NULL
;
415 pos
= maxlen
- len
- sizeof(".fake");
416 if (!dll_name_WtoA( file
+ pos
, name
, len
)) goto done
;
421 strcpy( file
+ pos
+ len
+ 1, ".fake" );
426 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".dll", 4 )) namelen
-= 4;
427 ptr
= prepend( ptr
, ptr
, namelen
);
428 ptr
= prepend( ptr
, "/dlls", sizeof("/dlls") - 1 );
429 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
430 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
432 /* now as a program */
435 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".exe", 4 )) namelen
-= 4;
436 ptr
= prepend( ptr
, ptr
, namelen
);
437 ptr
= prepend( ptr
, "/programs", sizeof("/programs") - 1 );
438 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
439 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
442 file
[pos
+ len
+ 1] = 0;
443 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
445 ptr
= prepend( file
+ pos
, "/fakedlls", sizeof("/fakedlls") - 1 );
446 ptr
= prepend( ptr
, path
, strlen(path
) );
447 if ((res
= read_file( ptr
, &data
, size
))) break;
451 HeapFree( GetProcessHeap(), 0, file
);
452 if (res
== 1) return data
;
456 /* create the fake dll destination file */
457 static HANDLE
create_dest_file( const WCHAR
*name
)
459 /* first check for an existing file */
460 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
461 if (h
!= INVALID_HANDLE_VALUE
)
463 if (!is_fake_dll( h
))
465 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
469 /* truncate the file */
470 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
475 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
477 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
478 if (h
== INVALID_HANDLE_VALUE
)
479 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
484 /* XML parsing code copied from ntdll */
498 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
500 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
503 static inline BOOL
isxmlspace( char ch
)
505 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
508 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
514 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
517 xmlbuf
->ptr
= xmlbuf
->end
;
521 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
523 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
524 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
526 if (ptr
+ 3 > xmlbuf
->end
)
528 xmlbuf
->ptr
= xmlbuf
->end
;
531 xmlbuf
->ptr
= ptr
+ 3;
537 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
540 elem
->ptr
= xmlbuf
->ptr
;
541 elem
->len
= ptr
- xmlbuf
->ptr
;
543 return xmlbuf
->ptr
!= xmlbuf
->end
;
546 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
,
547 BOOL
* error
, BOOL
* end
)
553 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
556 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
558 if (*xmlbuf
->ptr
== '/')
561 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
570 if (*xmlbuf
->ptr
== '>')
578 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
580 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
582 name
->ptr
= xmlbuf
->ptr
;
583 name
->len
= ptr
-xmlbuf
->ptr
;
587 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
590 if (ptr
== xmlbuf
->end
) return FALSE
;
592 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
595 xmlbuf
->ptr
= xmlbuf
->end
;
599 value
->len
= ptr
- value
->ptr
;
600 xmlbuf
->ptr
= ptr
+ 1;
602 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
608 static void get_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
609 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
611 static const WCHAR trailerW
[] = {'_','d','e','a','d','b','e','e','f',0};
614 pos
= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
, size
);
616 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
618 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
620 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
622 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
623 memcpy( buffer
+ pos
, trailerW
, sizeof(trailerW
) );
627 static BOOL
create_winsxs_dll( const WCHAR
*dll_name
, const xmlstr_t
*arch
, const xmlstr_t
*name
,
628 const xmlstr_t
*key
, const xmlstr_t
*version
, const xmlstr_t
*lang
,
629 const void *dll_data
, size_t dll_size
)
631 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\'};
633 const WCHAR
*filename
;
634 DWORD pos
, written
, path_len
;
638 if (!(filename
= strrchrW( dll_name
, '\\' ))) filename
= dll_name
;
641 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
642 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + strlenW( filename
) + 1;
644 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
645 pos
= GetWindowsDirectoryW( path
, path_len
);
647 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
648 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
649 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, path_len
- pos
);
650 pos
+= strlenW( path
+ pos
);
652 strcpyW( path
+ pos
, filename
);
653 handle
= create_dest_file( path
);
654 if (handle
&& handle
!= INVALID_HANDLE_VALUE
)
656 TRACE( "creating %s\n", debugstr_w(path
) );
657 ret
= (WriteFile( handle
, dll_data
, dll_size
, &written
, NULL
) && written
== dll_size
);
658 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
659 CloseHandle( handle
);
660 if (!ret
) DeleteFileW( path
);
662 HeapFree( GetProcessHeap(), 0, path
);
666 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
667 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
669 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s','\\'};
670 static const WCHAR extensionW
[] = {'.','m','a','n','i','f','e','s','t',0};
672 DWORD pos
, written
, path_len
;
676 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
677 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + sizeof(extensionW
)/sizeof(WCHAR
);
679 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
680 pos
= GetWindowsDirectoryW( path
, MAX_PATH
);
682 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
683 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
684 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, MAX_PATH
- pos
);
685 strcatW( path
+ pos
, extensionW
);
686 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
687 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
689 create_directories( path
);
690 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
693 if (handle
!= INVALID_HANDLE_VALUE
)
695 TRACE( "creating %s\n", debugstr_w(path
) );
696 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
697 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
698 CloseHandle( handle
);
699 if (!ret
) DeleteFileW( path
);
701 HeapFree( GetProcessHeap(), 0, path
);
705 static void register_manifest( const WCHAR
*dll_name
, const char *manifest
, DWORD len
,
706 const void *dll_data
, size_t dll_size
)
709 static const char current_arch
[] = "x86";
710 #elif defined __x86_64__
711 static const char current_arch
[] = "amd64";
713 static const char current_arch
[] = "none";
716 xmlstr_t elem
, attr_name
, attr_value
;
717 xmlstr_t name
, version
, arch
, key
, lang
;
718 BOOL end
= FALSE
, error
;
720 buffer
.ptr
= manifest
;
721 buffer
.end
= manifest
+ len
;
722 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
723 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
725 while (next_xml_elem( &buffer
, &elem
))
727 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
728 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
, &end
))
730 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
731 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
732 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
733 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
734 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
736 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
741 lang
.len
= strlen( lang
.ptr
);
743 if (!arch
.len
) /* fixup the architecture */
745 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
746 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
747 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
748 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
749 arch
.ptr
= current_arch
;
750 arch
.len
= strlen( current_arch
);
751 if (create_winsxs_dll( dll_name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
, dll_size
))
752 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
753 HeapFree( GetProcessHeap(), 0, new_buffer
);
757 if (create_winsxs_dll( dll_name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
, dll_size
))
758 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
764 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
766 HRESULT
*hr
= (HRESULT
*)arg
;
768 HRSRC rsrc
= FindResourceW( module
, name
, type
);
769 char *str
= LoadResource( module
, rsrc
);
770 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
772 if (!str
) return FALSE
;
773 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
774 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
775 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
776 buffer
[lenW
- 1] = 0;
777 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
778 HeapFree( GetProcessHeap(), 0, buffer
);
782 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
)
784 static const WCHAR atlW
[] = {'a','t','l','1','0','0','.','d','l','l',0};
785 static const WCHAR moduleW
[] = {'M','O','D','U','L','E',0};
786 static const WCHAR regtypeW
[] = {'W','I','N','E','_','R','E','G','I','S','T','R','Y',0};
787 static const WCHAR manifestW
[] = {'W','I','N','E','_','M','A','N','I','F','E','S','T',0};
788 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
789 LDR_RESOURCE_INFO info
;
791 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
794 if ((rsrc
= FindResourceW( module
, manifestW
, MAKEINTRESOURCEW(RT_MANIFEST
) )))
796 char *manifest
= LoadResource( module
, rsrc
);
797 register_manifest( name
, manifest
, SizeofResource( module
, rsrc
), data
, size
);
800 info
.Type
= (ULONG_PTR
)regtypeW
;
801 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
805 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
806 HMODULE atl
= LoadLibraryW( atlW
);
808 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
809 hr
= pAtlCreateRegistrar( ®istrar
);
815 ERR( "failed to create IRegistrar: %x\n", hr
);
820 TRACE( "registering %s\n", debugstr_w(name
) );
821 IRegistrar_ClearReplacements( registrar
);
822 IRegistrar_AddReplacement( registrar
, moduleW
, name
);
823 EnumResourceNamesW( module
, regtypeW
, register_resource
, (LONG_PTR
)&hr
);
824 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
827 /* copy a fake dll file to the dest directory */
828 static void install_fake_dll( WCHAR
*dest
, char *file
, const char *ext
)
834 WCHAR
*destname
= dest
+ strlenW(dest
);
835 char *name
= strrchr( file
, '/' ) + 1;
836 char *end
= name
+ strlen(name
);
838 if (ext
) strcpy( end
, ext
);
839 if (!(ret
= read_file( file
, &data
, &size
))) return;
841 if (end
> name
+ 2 && !strncmp( end
- 2, "16", 2 )) end
-= 2; /* remove "16" suffix */
842 dll_name_AtoW( destname
, name
, end
- name
);
843 if (!add_handled_dll( destname
)) ret
= -1;
847 HANDLE h
= create_dest_file( dest
);
849 if (h
&& h
!= INVALID_HANDLE_VALUE
)
851 TRACE( "%s -> %s\n", debugstr_a(file
), debugstr_w(dest
) );
853 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
854 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
856 if (ret
) register_fake_dll( dest
, data
, size
);
857 else DeleteFileW( dest
);
860 *destname
= 0; /* restore it for next file */
863 /* find and install all fake dlls in a given lib directory */
864 static void install_lib_dir( WCHAR
*dest
, char *file
, const char *default_ext
)
870 if (!(dir
= opendir( file
))) return;
871 name
= file
+ strlen(file
);
873 while ((de
= readdir( dir
)))
875 if (strlen( de
->d_name
) > max_dll_name_len
) continue;
876 if (!strcmp( de
->d_name
, "." )) continue;
877 if (!strcmp( de
->d_name
, ".." )) continue;
878 strcpy( name
, de
->d_name
);
879 if (default_ext
) /* inside build dir */
882 strcat( name
, de
->d_name
);
883 if (!strchr( de
->d_name
, '.' )) strcat( name
, default_ext
);
884 install_fake_dll( dest
, file
, ".fake" );
886 else install_fake_dll( dest
, file
, NULL
);
891 /* create fake dlls in dirname for all the files we can find */
892 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
)
894 const char *build_dir
= wine_get_build_dir();
896 unsigned int i
, maxlen
= 0;
900 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/");
901 for (i
= 0; (path
= wine_dll_enum_load_path(i
)); i
++) maxlen
= max( maxlen
, strlen(path
) );
902 maxlen
+= 2 * max_dll_name_len
+ 2 + sizeof(".dll.fake");
903 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return FALSE
;
905 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (strlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
907 HeapFree( GetProcessHeap(), 0, file
);
910 strcpyW( dest
, dirname
);
911 dest
[strlenW(dest
) - 1] = 0; /* remove wildcard */
915 strcpy( file
, build_dir
);
916 strcat( file
, "/dlls" );
917 install_lib_dir( dest
, file
, ".dll" );
918 strcpy( file
, build_dir
);
919 strcat( file
, "/programs" );
920 install_lib_dir( dest
, file
, ".exe" );
922 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
924 strcpy( file
, path
);
925 strcat( file
, "/fakedlls" );
926 install_lib_dir( dest
, file
, NULL
);
928 HeapFree( GetProcessHeap(), 0, file
);
929 HeapFree( GetProcessHeap(), 0, dest
);
933 /***********************************************************************
936 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
941 const WCHAR
*filename
;
944 if (!(filename
= strrchrW( name
, '\\' ))) filename
= name
;
947 /* check for empty name which means to only create the directory */
950 create_directories( name
);
953 if (filename
[0] == '*' && !filename
[1]) return create_wildcard_dlls( name
);
955 add_handled_dll( filename
);
957 if (!(h
= create_dest_file( name
))) return TRUE
; /* not a fake dll */
958 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
960 if (source
[0] == '-' && !source
[1])
962 /* '-' source means delete the file */
963 TRACE( "deleting %s\n", debugstr_w(name
) );
966 else if ((buffer
= load_fake_dll( source
, &size
)))
970 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
971 if (ret
) register_fake_dll( name
, buffer
, size
);
972 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
976 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
977 ret
= build_fake_dll( h
, name
);
981 if (!ret
) DeleteFileW( name
);
986 /***********************************************************************
989 void cleanup_fake_dlls(void)
991 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
993 HeapFree( GetProcessHeap(), 0, handled_dlls
);
995 handled_count
= handled_total
= 0;
996 if (registrar
) IRegistrar_Release( registrar
);