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
)
250 IMAGE_DOS_HEADER
*dos
;
251 IMAGE_NT_HEADERS
*nt
;
252 struct dll_info info
;
255 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
256 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
259 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
261 dos
= (IMAGE_DOS_HEADER
*)buffer
;
262 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
263 dos
->e_cblp
= sizeof(*dos
);
265 dos
->e_cparhdr
= lfanew
/ 16;
267 dos
->e_maxalloc
= 0xffff;
270 dos
->e_lfarlc
= lfanew
;
271 dos
->e_lfanew
= lfanew
;
272 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
274 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
275 /* some fields are copied from the source dll */
277 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
279 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
281 nt
->FileHeader
.TimeDateStamp
= 0;
282 nt
->FileHeader
.Characteristics
= IMAGE_FILE_DLL
;
283 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
284 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
285 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
286 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
287 nt
->OptionalHeader
.MajorImageVersion
= 1;
288 nt
->OptionalHeader
.MinorImageVersion
= 0;
289 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
290 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
291 nt
->OptionalHeader
.Win32VersionValue
= 0;
292 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
293 nt
->OptionalHeader
.DllCharacteristics
= 0;
294 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
295 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
296 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
297 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
298 /* other fields have fixed values */
299 nt
->Signature
= IMAGE_NT_SIGNATURE
;
300 nt
->FileHeader
.NumberOfSections
= 0;
301 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
302 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
303 nt
->OptionalHeader
.ImageBase
= 0x10000000;
304 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
305 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
306 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
308 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
309 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
310 info
.file_pos
= ALIGN( header_size
, file_alignment
);
312 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
313 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
315 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
317 size
= sizeof(dll_code_section
);
318 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
322 size
= sizeof(exe_code_section
);
323 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
325 nt
->OptionalHeader
.SizeOfCode
= size
;
326 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
328 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
329 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
330 add_section( &info
, ".reloc", sizeof(reloc_section
),
331 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
333 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
334 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
335 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
336 ret
= xwrite( &info
, buffer
, header_size
, 0 );
338 HeapFree( GetProcessHeap(), 0, buffer
);
342 /* check if an existing file is a fake dll so that we can overwrite it */
343 static BOOL
is_fake_dll( HANDLE h
)
345 IMAGE_DOS_HEADER
*dos
;
347 BYTE buffer
[sizeof(*dos
) + sizeof(fakedll_signature
)];
349 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
351 dos
= (IMAGE_DOS_HEADER
*)buffer
;
352 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
353 if (dos
->e_lfanew
< size
) return FALSE
;
354 return !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
357 /* create directories leading to a given file */
358 static void create_directories( const WCHAR
*name
)
362 /* create the directory/directories */
363 path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1)*sizeof(WCHAR
));
366 p
= strchrW(path
, '\\');
370 if (!CreateDirectoryW(path
, NULL
))
371 TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path
), GetLastError());
373 p
= strchrW(p
+1, '\\');
375 HeapFree(GetProcessHeap(), 0, path
);
378 static inline char *prepend( char *buffer
, const char *str
, size_t len
)
380 return memcpy( buffer
- len
, str
, len
);
383 /* try to load a pre-compiled fake dll */
384 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
386 const char *build_dir
= wine_get_build_dir();
390 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
394 if ((p
= strrchrW( name
, '\\' ))) name
= p
+ 1;
397 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/") + strlenW(name
);
398 while ((path
= wine_dll_enum_load_path( i
++ ))) maxlen
= max( maxlen
, strlen(path
) );
399 maxlen
+= sizeof("/fakedlls") + strlenW(name
) + 2;
401 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return NULL
;
403 len
= strlenW( name
);
404 pos
= maxlen
- len
- sizeof(".fake");
405 if (!dll_name_WtoA( file
+ pos
, name
, len
)) goto done
;
410 strcpy( file
+ pos
+ len
+ 1, ".fake" );
415 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".dll", 4 )) namelen
-= 4;
416 ptr
= prepend( ptr
, ptr
, namelen
);
417 ptr
= prepend( ptr
, "/dlls", sizeof("/dlls") - 1 );
418 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
419 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
421 /* now as a program */
424 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".exe", 4 )) namelen
-= 4;
425 ptr
= prepend( ptr
, ptr
, namelen
);
426 ptr
= prepend( ptr
, "/programs", sizeof("/programs") - 1 );
427 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
428 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
431 file
[pos
+ len
+ 1] = 0;
432 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
434 ptr
= prepend( file
+ pos
, "/fakedlls", sizeof("/fakedlls") - 1 );
435 ptr
= prepend( ptr
, path
, strlen(path
) );
436 if ((res
= read_file( ptr
, &data
, size
))) break;
440 HeapFree( GetProcessHeap(), 0, file
);
441 if (res
== 1) return data
;
445 /* create the fake dll destination file */
446 static HANDLE
create_dest_file( const WCHAR
*name
)
448 /* first check for an existing file */
449 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
450 if (h
!= INVALID_HANDLE_VALUE
)
452 if (!is_fake_dll( h
))
454 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
458 /* truncate the file */
459 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
464 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
466 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
467 if (h
== INVALID_HANDLE_VALUE
)
468 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
473 /* XML parsing code copied from ntdll */
487 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
489 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
492 static inline BOOL
isxmlspace( char ch
)
494 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
497 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
503 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
506 xmlbuf
->ptr
= xmlbuf
->end
;
510 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
512 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
513 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
515 if (ptr
+ 3 > xmlbuf
->end
)
517 xmlbuf
->ptr
= xmlbuf
->end
;
520 xmlbuf
->ptr
= ptr
+ 3;
526 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
529 elem
->ptr
= xmlbuf
->ptr
;
530 elem
->len
= ptr
- xmlbuf
->ptr
;
532 return xmlbuf
->ptr
!= xmlbuf
->end
;
535 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
,
536 BOOL
* error
, BOOL
* end
)
542 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
545 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
547 if (*xmlbuf
->ptr
== '/')
550 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
559 if (*xmlbuf
->ptr
== '>')
567 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
569 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
571 name
->ptr
= xmlbuf
->ptr
;
572 name
->len
= ptr
-xmlbuf
->ptr
;
576 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
579 if (ptr
== xmlbuf
->end
) return FALSE
;
581 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
584 xmlbuf
->ptr
= xmlbuf
->end
;
588 value
->len
= ptr
- value
->ptr
;
589 xmlbuf
->ptr
= ptr
+ 1;
591 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
597 static void get_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
598 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
600 static const WCHAR trailerW
[] = {'_','d','e','a','d','b','e','e','f',0};
603 pos
= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
, size
);
605 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
607 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
609 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
611 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
612 memcpy( buffer
+ pos
, trailerW
, sizeof(trailerW
) );
616 static BOOL
create_winsxs_dll( const WCHAR
*dll_name
, const xmlstr_t
*arch
, const xmlstr_t
*name
,
617 const xmlstr_t
*key
, const xmlstr_t
*version
, const xmlstr_t
*lang
,
618 const void *dll_data
, size_t dll_size
)
620 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\'};
622 const WCHAR
*filename
;
623 DWORD pos
, written
, path_len
;
627 if (!(filename
= strrchrW( dll_name
, '\\' ))) filename
= dll_name
;
630 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
631 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + strlenW( filename
) + 1;
633 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
634 pos
= GetWindowsDirectoryW( path
, path_len
);
636 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
637 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
638 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, path_len
- pos
);
639 pos
+= strlenW( path
+ pos
);
641 strcpyW( path
+ pos
, filename
);
642 handle
= create_dest_file( path
);
643 if (handle
&& handle
!= INVALID_HANDLE_VALUE
)
645 TRACE( "creating %s\n", debugstr_w(path
) );
646 ret
= (WriteFile( handle
, dll_data
, dll_size
, &written
, NULL
) && written
== dll_size
);
647 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
648 CloseHandle( handle
);
649 if (!ret
) DeleteFileW( path
);
651 HeapFree( GetProcessHeap(), 0, path
);
655 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
656 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
658 static const WCHAR winsxsW
[] = {'w','i','n','s','x','s','\\','m','a','n','i','f','e','s','t','s','\\'};
659 static const WCHAR extensionW
[] = {'.','m','a','n','i','f','e','s','t',0};
661 DWORD pos
, written
, path_len
;
665 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + 1 + sizeof(winsxsW
)/sizeof(WCHAR
)
666 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + sizeof(extensionW
)/sizeof(WCHAR
);
668 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
669 pos
= GetWindowsDirectoryW( path
, MAX_PATH
);
671 memcpy( path
+ pos
, winsxsW
, sizeof(winsxsW
) );
672 pos
+= sizeof(winsxsW
) / sizeof(WCHAR
);
673 get_manifest_filename( arch
, name
, key
, version
, lang
, path
+ pos
, MAX_PATH
- pos
);
674 strcatW( path
+ pos
, extensionW
);
675 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
676 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
678 create_directories( path
);
679 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
682 if (handle
!= INVALID_HANDLE_VALUE
)
684 TRACE( "creating %s\n", debugstr_w(path
) );
685 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
686 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
687 CloseHandle( handle
);
688 if (!ret
) DeleteFileW( path
);
690 HeapFree( GetProcessHeap(), 0, path
);
694 static void register_manifest( const WCHAR
*dll_name
, const char *manifest
, DWORD len
,
695 const void *dll_data
, size_t dll_size
)
698 static const char current_arch
[] = "x86";
699 #elif defined __x86_64__
700 static const char current_arch
[] = "amd64";
702 static const char current_arch
[] = "none";
705 xmlstr_t elem
, attr_name
, attr_value
;
706 xmlstr_t name
, version
, arch
, key
, lang
;
707 BOOL end
= FALSE
, error
;
709 buffer
.ptr
= manifest
;
710 buffer
.end
= manifest
+ len
;
711 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
712 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
714 while (next_xml_elem( &buffer
, &elem
))
716 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
717 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
, &end
))
719 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
720 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
721 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
722 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
723 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
725 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
730 lang
.len
= strlen( lang
.ptr
);
732 if (!arch
.len
) /* fixup the architecture */
734 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
735 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
736 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
737 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
738 arch
.ptr
= current_arch
;
739 arch
.len
= strlen( current_arch
);
740 if (create_winsxs_dll( dll_name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
, dll_size
))
741 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
742 HeapFree( GetProcessHeap(), 0, new_buffer
);
746 if (create_winsxs_dll( dll_name
, &arch
, &name
, &key
, &version
, &lang
, dll_data
, dll_size
))
747 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
753 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
755 HRESULT
*hr
= (HRESULT
*)arg
;
757 HRSRC rsrc
= FindResourceW( module
, name
, type
);
758 char *str
= LoadResource( module
, rsrc
);
759 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
761 if (!str
) return FALSE
;
762 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
763 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
764 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
765 buffer
[lenW
- 1] = 0;
766 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
767 HeapFree( GetProcessHeap(), 0, buffer
);
771 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
)
773 static const WCHAR atlW
[] = {'a','t','l','.','d','l','l',0};
774 static const WCHAR moduleW
[] = {'M','O','D','U','L','E',0};
775 static const WCHAR regtypeW
[] = {'W','I','N','E','_','R','E','G','I','S','T','R','Y',0};
776 static const WCHAR manifestW
[] = {'W','I','N','E','_','M','A','N','I','F','E','S','T',0};
777 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
778 LDR_RESOURCE_INFO info
;
780 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
783 if ((rsrc
= FindResourceW( module
, manifestW
, MAKEINTRESOURCEW(RT_MANIFEST
) )))
785 char *manifest
= LoadResource( module
, rsrc
);
786 register_manifest( name
, manifest
, SizeofResource( module
, rsrc
), data
, size
);
789 info
.Type
= (ULONG_PTR
)regtypeW
;
790 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
794 /* create the object by hand since we can't guarantee that atl and ole32 are registered */
796 HRESULT (WINAPI
*pDllGetClassObject
)( REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
797 HMODULE atl
= LoadLibraryW( atlW
);
799 if ((pDllGetClassObject
= (void *)GetProcAddress( atl
, "DllGetClassObject" )))
801 hr
= pDllGetClassObject( &CLSID_Registrar
, &IID_IClassFactory
, (void **)&cf
);
804 hr
= IClassFactory_CreateInstance( cf
, NULL
, &IID_IRegistrar
, (void **)®istrar
);
805 IClassFactory_Release( cf
);
810 ERR( "failed to create IRegistrar: %x\n", hr
);
815 TRACE( "registering %s\n", debugstr_w(name
) );
816 IRegistrar_ClearReplacements( registrar
);
817 IRegistrar_AddReplacement( registrar
, moduleW
, name
);
818 EnumResourceNamesW( module
, regtypeW
, register_resource
, (LONG_PTR
)&hr
);
819 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
822 /* copy a fake dll file to the dest directory */
823 static void install_fake_dll( WCHAR
*dest
, char *file
, const char *ext
)
829 WCHAR
*destname
= dest
+ strlenW(dest
);
830 char *name
= strrchr( file
, '/' ) + 1;
831 char *end
= name
+ strlen(name
);
833 if (ext
) strcpy( end
, ext
);
834 if (!(ret
= read_file( file
, &data
, &size
))) return;
836 if (end
> name
+ 2 && !strncmp( end
- 2, "16", 2 )) end
-= 2; /* remove "16" suffix */
837 dll_name_AtoW( destname
, name
, end
- name
);
838 if (!add_handled_dll( destname
)) ret
= -1;
842 HANDLE h
= create_dest_file( dest
);
844 if (h
&& h
!= INVALID_HANDLE_VALUE
)
846 TRACE( "%s -> %s\n", debugstr_a(file
), debugstr_w(dest
) );
848 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
849 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
851 if (ret
) register_fake_dll( dest
, data
, size
);
852 else DeleteFileW( dest
);
855 *destname
= 0; /* restore it for next file */
858 /* find and install all fake dlls in a given lib directory */
859 static void install_lib_dir( WCHAR
*dest
, char *file
, const char *default_ext
)
865 if (!(dir
= opendir( file
))) return;
866 name
= file
+ strlen(file
);
868 while ((de
= readdir( dir
)))
870 if (strlen( de
->d_name
) > max_dll_name_len
) continue;
871 if (!strcmp( de
->d_name
, "." )) continue;
872 if (!strcmp( de
->d_name
, ".." )) continue;
873 strcpy( name
, de
->d_name
);
874 if (default_ext
) /* inside build dir */
877 strcat( name
, de
->d_name
);
878 if (!strchr( de
->d_name
, '.' )) strcat( name
, default_ext
);
879 install_fake_dll( dest
, file
, ".fake" );
881 else install_fake_dll( dest
, file
, NULL
);
886 /* create fake dlls in dirname for all the files we can find */
887 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
)
889 const char *build_dir
= wine_get_build_dir();
891 unsigned int i
, maxlen
= 0;
895 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/");
896 for (i
= 0; (path
= wine_dll_enum_load_path(i
)); i
++) maxlen
= max( maxlen
, strlen(path
) );
897 maxlen
+= 2 * max_dll_name_len
+ 2 + sizeof(".dll.fake");
898 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return FALSE
;
900 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (strlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
902 HeapFree( GetProcessHeap(), 0, file
);
905 strcpyW( dest
, dirname
);
906 dest
[strlenW(dest
) - 1] = 0; /* remove wildcard */
910 strcpy( file
, build_dir
);
911 strcat( file
, "/dlls" );
912 install_lib_dir( dest
, file
, ".dll" );
913 strcpy( file
, build_dir
);
914 strcat( file
, "/programs" );
915 install_lib_dir( dest
, file
, ".exe" );
917 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
919 strcpy( file
, path
);
920 strcat( file
, "/fakedlls" );
921 install_lib_dir( dest
, file
, NULL
);
923 HeapFree( GetProcessHeap(), 0, file
);
924 HeapFree( GetProcessHeap(), 0, dest
);
928 /***********************************************************************
931 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
936 const WCHAR
*filename
;
939 if (!(filename
= strrchrW( name
, '\\' ))) filename
= name
;
942 /* check for empty name which means to only create the directory */
945 create_directories( name
);
948 if (filename
[0] == '*' && !filename
[1]) return create_wildcard_dlls( name
);
950 add_handled_dll( filename
);
952 if (!(h
= create_dest_file( name
))) return TRUE
; /* not a fake dll */
953 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
955 if (source
[0] == '-' && !source
[1])
957 /* '-' source means delete the file */
958 TRACE( "deleting %s\n", debugstr_w(name
) );
961 else if ((buffer
= load_fake_dll( source
, &size
)))
965 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
966 if (ret
) register_fake_dll( name
, buffer
, size
);
967 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
971 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
972 ret
= build_fake_dll( h
);
976 if (!ret
) DeleteFileW( name
);
981 /***********************************************************************
984 void cleanup_fake_dlls(void)
986 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
988 HeapFree( GetProcessHeap(), 0, handled_dlls
);
990 handled_count
= handled_total
= 0;
991 if (registrar
) IRegistrar_Release( registrar
);