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
30 #define WIN32_NO_STATUS
36 #include "wine/debug.h"
37 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
44 static const WCHAR pe_dir
[] = L
"\\i386-windows";
45 static const char current_arch
[] = "x86";
46 #elif defined __x86_64__
47 static const WCHAR pe_dir
[] = L
"\\x86_64-windows";
48 static const char current_arch
[] = "amd64";
50 static const WCHAR pe_dir
[] = L
"\\arm-windows";
51 static const char current_arch
[] = "arm";
52 #elif defined __aarch64__
53 static const WCHAR pe_dir
[] = L
"\\aarch64-windows";
54 static const char current_arch
[] = "arm64";
56 static const WCHAR pe_dir
[] = L
"";
57 static const char current_arch
[] = "none";
60 static const char builtin_signature
[] = "Wine builtin DLL";
61 static const char fakedll_signature
[] = "Wine placeholder DLL";
63 static const unsigned int file_alignment
= 512;
64 static const unsigned int section_alignment
= 4096;
65 static const unsigned int max_dll_name_len
= 64;
67 static void *file_buffer
;
68 static SIZE_T file_buffer_size
;
69 static unsigned int handled_count
;
70 static unsigned int handled_total
;
71 static WCHAR
**handled_dlls
;
72 static IRegistrar
*registrar
;
82 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
84 /* contents of the dll sections */
86 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
87 0xc2, 0x0c, 0x00 }; /* ret $12 */
89 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
90 0xc2, 0x04, 0x00 }; /* ret $4 */
92 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
95 /* wrapper for WriteFile */
96 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
100 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
101 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
105 /* add a new section to the dll NT header */
106 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
108 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
110 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
111 memcpy( sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
112 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
113 sec
->VirtualAddress
= info
->mem_pos
;
114 sec
->SizeOfRawData
= size
;
115 sec
->PointerToRawData
= info
->file_pos
;
116 sec
->Characteristics
= flags
;
117 info
->file_pos
+= ALIGN( size
, file_alignment
);
118 info
->mem_pos
+= ALIGN( size
, section_alignment
);
119 info
->nt
->FileHeader
.NumberOfSections
++;
122 /* add a data directory to the dll NT header */
123 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
125 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
126 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
129 /* add a dll to the list of dll that have been taken care of */
130 static BOOL
add_handled_dll( const WCHAR
*name
)
132 int i
, min
, max
, pos
, res
;
135 max
= handled_count
- 1;
138 pos
= (min
+ max
) / 2;
139 res
= wcscmp( handled_dlls
[pos
], name
);
140 if (!res
) return FALSE
; /* already in the list */
141 if (res
< 0) min
= pos
+ 1;
145 if (handled_count
>= handled_total
)
148 unsigned int new_count
= max( 64, handled_total
* 2 );
150 if (handled_dlls
) new_dlls
= HeapReAlloc( GetProcessHeap(), 0, handled_dlls
,
151 new_count
* sizeof(*handled_dlls
) );
152 else new_dlls
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*handled_dlls
) );
153 if (!new_dlls
) return FALSE
;
154 handled_dlls
= new_dlls
;
155 handled_total
= new_count
;
158 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
159 handled_dlls
[i
] = wcsdup( name
);
164 static int is_valid_ptr( const void *data
, SIZE_T size
, const void *ptr
, SIZE_T ptr_size
)
166 if (ptr
< data
) return 0;
167 if ((char *)ptr
- (char *)data
>= size
) return 0;
168 return (size
- ((char *)ptr
- (char *)data
) >= ptr_size
);
171 /* extract the 16-bit NE dll from a PE builtin */
172 static void extract_16bit_image( IMAGE_NT_HEADERS
*nt
, void **data
, SIZE_T
*size
)
174 DWORD exp_size
, *size_ptr
;
175 IMAGE_DOS_HEADER
*dos
;
176 IMAGE_EXPORT_DIRECTORY
*exports
;
177 IMAGE_SECTION_HEADER
*section
= NULL
;
179 DWORD
*names
, *functions
;
182 exports
= RtlImageDirectoryEntryToData( *data
, FALSE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
183 if (!is_valid_ptr( *data
, *size
, exports
, exp_size
)) return;
184 ordinals
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNameOrdinals
, §ion
);
185 names
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNames
, §ion
);
186 functions
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfFunctions
, §ion
);
187 if (!is_valid_ptr( *data
, *size
, ordinals
, exports
->NumberOfNames
* sizeof(*ordinals
) )) return;
188 if (!is_valid_ptr( *data
, *size
, names
, exports
->NumberOfNames
* sizeof(*names
) )) return;
190 for (i
= 0; i
< exports
->NumberOfNames
; i
++)
192 char *ename
= RtlImageRvaToVa( nt
, *data
, names
[i
], §ion
);
193 if (strcmp( ename
, "__wine_spec_dos_header" )) continue;
194 if (ordinals
[i
] >= exports
->NumberOfFunctions
) return;
195 if (!is_valid_ptr( *data
, *size
, functions
, sizeof(*functions
) )) return;
196 if (!functions
[ordinals
[i
]]) return;
197 dos
= RtlImageRvaToVa( nt
, *data
, functions
[ordinals
[i
]], NULL
);
198 if (!is_valid_ptr( *data
, *size
, dos
, sizeof(*dos
) )) return;
199 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return;
200 size_ptr
= (DWORD
*)dos
->e_res2
;
201 *size
= min( *size_ptr
, *size
- ((const char *)dos
- (const char *)*data
) );
208 /* read in the contents of a file into the global file buffer */
209 /* return 1 on success, 0 on nonexistent file, -1 on other error */
210 static int read_file( const WCHAR
*name
, void **data
, SIZE_T
*size
)
215 IMAGE_DOS_HEADER
*dos
;
216 IMAGE_NT_HEADERS
*nt
;
217 const size_t min_size
= sizeof(*dos
) + 32 +
218 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
220 if ((fd
= _wopen( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
221 if (fstat( fd
, &st
) == -1) goto done
;
223 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
225 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
227 file_buffer_size
= st
.st_size
;
228 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
229 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
232 /* check for valid fake dll file */
234 if (st
.st_size
< min_size
) goto done
;
235 header_size
= min( st
.st_size
, 4096 );
236 if (read( fd
, file_buffer
, header_size
) != header_size
) goto done
;
238 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
239 if (dos
->e_lfanew
< sizeof(*dos
) + 32) goto done
;
240 if (memcmp( dos
+ 1, builtin_signature
, strlen(builtin_signature
) + 1 ) &&
241 memcmp( dos
+ 1, fakedll_signature
, strlen(fakedll_signature
) + 1 )) goto done
;
242 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
244 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
245 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
247 /* wrong 32/64 type, pretend it doesn't exist */
251 if (st
.st_size
== header_size
||
252 read( fd
, (char *)file_buffer
+ header_size
,
253 st
.st_size
- header_size
) == st
.st_size
- header_size
)
256 if (lstrlenW(name
) > 2 && !wcscmp( name
+ lstrlenW(name
) - 2, L
"16" ))
257 extract_16bit_image( nt
, data
, size
);
265 /* build a complete fake dll from scratch */
266 static BOOL
build_fake_dll( HANDLE file
, const WCHAR
*name
)
268 IMAGE_DOS_HEADER
*dos
;
269 IMAGE_NT_HEADERS
*nt
;
270 struct dll_info info
;
274 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
275 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
278 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
280 dos
= (IMAGE_DOS_HEADER
*)buffer
;
281 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
282 dos
->e_cblp
= sizeof(*dos
);
284 dos
->e_cparhdr
= lfanew
/ 16;
286 dos
->e_maxalloc
= 0xffff;
289 dos
->e_lfarlc
= lfanew
;
290 dos
->e_lfanew
= lfanew
;
291 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
293 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
294 /* some fields are copied from the source dll */
295 #if defined __x86_64__
296 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
297 #elif defined __aarch64__
298 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARM64
;
299 #elif defined __arm__
300 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARMNT
;
302 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
304 nt
->FileHeader
.TimeDateStamp
= 0;
305 nt
->FileHeader
.Characteristics
= 0;
306 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
307 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
308 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
309 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
310 nt
->OptionalHeader
.MajorImageVersion
= 1;
311 nt
->OptionalHeader
.MinorImageVersion
= 0;
312 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
313 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
314 nt
->OptionalHeader
.Win32VersionValue
= 0;
315 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
316 nt
->OptionalHeader
.DllCharacteristics
= 0;
317 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
318 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
319 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
320 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
321 /* other fields have fixed values */
322 nt
->Signature
= IMAGE_NT_SIGNATURE
;
323 nt
->FileHeader
.NumberOfSections
= 0;
324 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
325 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
326 nt
->OptionalHeader
.ImageBase
= 0x10000000;
327 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
328 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
329 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
331 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
332 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
333 info
.file_pos
= ALIGN( header_size
, file_alignment
);
335 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
336 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
338 ext
= wcsrchr( name
, '.' );
339 if (!ext
|| wcsicmp( ext
, L
".exe" )) nt
->FileHeader
.Characteristics
|= IMAGE_FILE_DLL
;
341 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
343 size
= sizeof(dll_code_section
);
344 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
348 size
= sizeof(exe_code_section
);
349 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
351 nt
->OptionalHeader
.SizeOfCode
= size
;
352 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
354 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
355 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
356 add_section( &info
, ".reloc", sizeof(reloc_section
),
357 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
359 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
360 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
361 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
362 ret
= xwrite( &info
, buffer
, header_size
, 0 );
364 HeapFree( GetProcessHeap(), 0, buffer
);
368 /* check if an existing file is a fake dll so that we can overwrite it */
369 static BOOL
is_fake_dll( HANDLE h
)
371 IMAGE_DOS_HEADER
*dos
;
373 BYTE buffer
[sizeof(*dos
) + 32];
375 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
377 dos
= (IMAGE_DOS_HEADER
*)buffer
;
378 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
379 if (dos
->e_lfanew
< size
) return FALSE
;
380 return (!memcmp( dos
+ 1, builtin_signature
, sizeof(builtin_signature
) ) ||
381 !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) ));
384 /* create directories leading to a given file */
385 static void create_directories( const WCHAR
*name
)
389 /* create the directory/directories */
390 path
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name
) + 1)*sizeof(WCHAR
));
391 lstrcpyW(path
, name
);
393 p
= wcschr(path
, '\\');
397 if (!CreateDirectoryW(path
, NULL
))
398 TRACE("Couldn't create directory %s - error: %ld\n", wine_dbgstr_w(path
), GetLastError());
400 p
= wcschr(p
+1, '\\');
402 HeapFree(GetProcessHeap(), 0, path
);
405 static inline WCHAR
*prepend( WCHAR
*buffer
, const WCHAR
*str
, size_t len
)
407 return memcpy( buffer
- len
, str
, len
* sizeof(WCHAR
) );
410 static const WCHAR
*enum_load_path( unsigned int idx
)
413 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"WINEDLLDIR%u", idx
);
414 return _wgetenv( buffer
);
417 /* try to load a pre-compiled fake dll */
418 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
420 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
424 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
428 if ((p
= wcsrchr( name
, '\\' ))) name
= p
+ 1;
431 len
= lstrlenW( name
);
432 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + len
+ 1;
433 while ((path
= enum_load_path( i
++ ))) maxlen
= max( maxlen
, lstrlenW(path
) );
434 maxlen
+= ARRAY_SIZE(pe_dir
) + len
+ 1;
436 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return NULL
;
438 pos
= maxlen
- len
- 1;
439 lstrcpyW( file
+ pos
, name
);
447 file
[pos
+ len
+ 1] = 0;
448 if (namelen
> 4 && !wcsncmp( ptr
+ namelen
- 4, L
".dll", 4 )) namelen
-= 4;
449 ptr
= prepend( ptr
, ptr
, namelen
);
450 ptr
= prepend( ptr
, L
"\\dlls", 5 );
451 ptr
= prepend( ptr
, build_dir
, lstrlenW(build_dir
) );
452 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
454 /* now as a program */
457 file
[pos
+ len
+ 1] = 0;
458 if (namelen
> 4 && !wcsncmp( ptr
+ namelen
- 4, L
".exe", 4 )) namelen
-= 4;
459 ptr
= prepend( ptr
, ptr
, namelen
);
460 ptr
= prepend( ptr
, L
"\\programs", 9 );
461 ptr
= prepend( ptr
, build_dir
, lstrlenW(build_dir
) );
462 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
465 file
[pos
+ len
+ 1] = 0;
466 for (i
= 0; (path
= enum_load_path( i
)); i
++)
468 ptr
= prepend( file
+ pos
, pe_dir
, lstrlenW(pe_dir
) );
469 ptr
= prepend( ptr
, path
, lstrlenW(path
) );
470 if ((res
= read_file( ptr
, &data
, size
))) break;
471 ptr
= prepend( file
+ pos
, path
, lstrlenW(path
) );
472 if ((res
= read_file( ptr
, &data
, size
))) break;
476 HeapFree( GetProcessHeap(), 0, file
);
477 if (res
== 1) return data
;
481 /* create the fake dll destination file */
482 static HANDLE
create_dest_file( const WCHAR
*name
, BOOL
delete )
484 /* first check for an existing file */
485 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
486 if (h
!= INVALID_HANDLE_VALUE
)
488 if (!is_fake_dll( h
))
490 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
498 return INVALID_HANDLE_VALUE
;
500 /* truncate the file */
501 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
506 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
508 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
509 if (h
== INVALID_HANDLE_VALUE
)
510 ERR( "failed to create %s (error=%lu)\n", debugstr_w(name
), GetLastError() );
515 /* XML parsing code copied from ntdll */
529 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
531 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
534 static inline BOOL
isxmlspace( char ch
)
536 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
539 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
545 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
548 xmlbuf
->ptr
= xmlbuf
->end
;
552 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
554 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
555 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
557 if (ptr
+ 3 > xmlbuf
->end
)
559 xmlbuf
->ptr
= xmlbuf
->end
;
562 xmlbuf
->ptr
= ptr
+ 3;
568 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
571 elem
->ptr
= xmlbuf
->ptr
;
572 elem
->len
= ptr
- xmlbuf
->ptr
;
574 return xmlbuf
->ptr
!= xmlbuf
->end
;
577 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
, BOOL
* error
)
583 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
586 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
588 if (*xmlbuf
->ptr
== '/')
591 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
599 if (*xmlbuf
->ptr
== '>')
607 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
609 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
611 name
->ptr
= xmlbuf
->ptr
;
612 name
->len
= ptr
-xmlbuf
->ptr
;
616 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
619 if (ptr
== xmlbuf
->end
) return FALSE
;
621 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
624 xmlbuf
->ptr
= xmlbuf
->end
;
628 value
->len
= ptr
- value
->ptr
;
629 xmlbuf
->ptr
= ptr
+ 1;
631 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
637 static void append_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
638 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
640 DWORD pos
= lstrlenW( buffer
);
642 pos
+= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
+ pos
, size
- pos
);
644 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
646 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
648 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
650 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
651 lstrcpyW( buffer
+ pos
, L
"_deadbeef" );
655 static WCHAR
* create_winsxs_dll_path( const xmlstr_t
*arch
, const xmlstr_t
*name
,
656 const xmlstr_t
*key
, const xmlstr_t
*version
,
657 const xmlstr_t
*lang
)
662 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\" )
663 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 19;
665 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
666 GetWindowsDirectoryW( path
, path_len
);
667 lstrcatW( path
, L
"\\winsxs\\" );
668 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
669 lstrcatW( path
, L
"\\" );
673 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
674 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
677 DWORD written
, path_len
;
681 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\manifests\\" )
682 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + ARRAY_SIZE( L
".manifest" );
684 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
685 GetWindowsDirectoryW( path
, path_len
);
686 lstrcatW( path
, L
"\\winsxs\\manifests\\" );
687 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
688 lstrcatW( path
, L
".manifest" );
689 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
690 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
692 create_directories( path
);
693 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
696 if (handle
!= INVALID_HANDLE_VALUE
)
698 TRACE( "creating %s\n", debugstr_w(path
) );
699 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
700 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(path
), GetLastError() );
701 CloseHandle( handle
);
702 if (!ret
) DeleteFileW( path
);
704 HeapFree( GetProcessHeap(), 0, path
);
718 struct list
*delay_copy
;
719 const WCHAR
*src_dir
;
723 static BOOL CALLBACK
register_manifest( HMODULE module
, const WCHAR
*type
, WCHAR
*res_name
, LONG_PTR arg
)
725 const struct dll_data
*dll_data
= (const struct dll_data
*)arg
;
729 xmlstr_t elem
, attr_name
, attr_value
;
730 xmlstr_t name
, version
, arch
, key
, lang
;
732 const char *manifest
;
736 if (IS_INTRESOURCE( res_name
) || wcsncmp( res_name
, L
"WINE_MANIFEST", 13 )) return TRUE
;
738 rsrc
= FindResourceW( module
, res_name
, type
);
739 manifest
= LoadResource( module
, rsrc
);
740 len
= SizeofResource( module
, rsrc
);
742 buffer
.ptr
= manifest
;
743 buffer
.end
= manifest
+ len
;
744 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
745 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
747 while (next_xml_elem( &buffer
, &elem
))
749 if (xmlstr_cmp( &elem
, "file" ))
751 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
753 if (xmlstr_cmp(&attr_name
, "name"))
760 if (!error
&& dest
&& name
.ptr
)
762 struct delay_copy
*add
= HeapAlloc( GetProcessHeap(), 0,
763 sizeof(*add
) + (dll_data
->src_len
+ name
.len
+
764 dest_len
+ name
.len
+ 1) * sizeof(WCHAR
) );
765 add
->src
= add
->data
;
766 memcpy( add
->src
, dll_data
->src_dir
, dll_data
->src_len
* sizeof(WCHAR
) );
767 MultiByteToWideChar( CP_UTF8
, 0, name
.ptr
, name
.len
,
768 add
->src
+ dll_data
->src_len
, name
.len
);
769 add
->src
[dll_data
->src_len
+ name
.len
] = 0;
770 add
->dest
= add
->data
+ dll_data
->src_len
+ name
.len
+ 1;
771 memcpy( add
->dest
, dest
, dest_len
* sizeof(WCHAR
) );
772 memcpy( add
->dest
+ dest_len
, add
->src
+ dll_data
->src_len
,
773 (name
.len
+ 1) * sizeof(WCHAR
) );
774 TRACE("schedule copy %s -> %s\n", wine_dbgstr_w(add
->src
), wine_dbgstr_w(add
->dest
));
775 list_add_tail( dll_data
->delay_copy
, &add
->entry
);
780 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
781 HeapFree( GetProcessHeap(), 0, dest
);
783 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
785 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
786 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
787 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
788 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
789 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
791 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
796 lang
.len
= strlen( lang
.ptr
);
798 if (!arch
.len
) /* fixup the architecture */
800 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
801 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
802 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
803 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
804 arch
.ptr
= current_arch
;
805 arch
.len
= strlen( current_arch
);
806 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
807 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
808 HeapFree( GetProcessHeap(), 0, new_buffer
);
812 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
813 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
815 dest_len
= wcslen( dest
);
818 HeapFree( GetProcessHeap(), 0, dest
);
823 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
825 HRESULT
*hr
= (HRESULT
*)arg
;
827 HRSRC rsrc
= FindResourceW( module
, name
, type
);
828 char *str
= LoadResource( module
, rsrc
);
829 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
831 if (!str
) return FALSE
;
832 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
833 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
834 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
835 buffer
[lenW
- 1] = 0;
836 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
837 HeapFree( GetProcessHeap(), 0, buffer
);
841 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
, struct list
*delay_copy
)
843 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
844 LDR_RESOURCE_INFO info
;
846 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
847 struct dll_data dll_data
= { delay_copy
, name
, 0 };
848 WCHAR buffer
[MAX_PATH
];
851 if (!(p
= wcsrchr( name
, '\\' ))) p
= name
;
853 dll_data
.src_len
= p
- name
;
854 EnumResourceNamesW( module
, (WCHAR
*)RT_MANIFEST
, register_manifest
, (LONG_PTR
)&dll_data
);
856 info
.Type
= (ULONG_PTR
)L
"WINE_REGISTRY";
857 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
861 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
862 HMODULE atl
= LoadLibraryW( L
"atl100.dll" );
864 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
865 hr
= pAtlCreateRegistrar( ®istrar
);
871 ERR( "failed to create IRegistrar: %lx\n", hr
);
876 TRACE( "registering %s\n", debugstr_w(name
) );
877 IRegistrar_ClearReplacements( registrar
);
878 IRegistrar_AddReplacement( registrar
, L
"MODULE", name
);
879 GetEnvironmentVariableW( L
"SystemRoot", buffer
, ARRAY_SIZE(buffer
) );
880 IRegistrar_AddReplacement( registrar
, L
"SystemRoot", buffer
);
881 EnumResourceNamesW( module
, L
"WINE_REGISTRY", register_resource
, (LONG_PTR
)&hr
);
882 if (FAILED(hr
)) ERR( "failed to register %s: %lx\n", debugstr_w(name
), hr
);
885 /* copy a fake dll file to the dest directory */
886 static int install_fake_dll( WCHAR
*dest
, WCHAR
*file
, BOOL
delete, struct list
*delay_copy
)
892 WCHAR
*destname
= dest
+ lstrlenW(dest
);
893 WCHAR
*name
= wcsrchr( file
, '\\' ) + 1;
894 WCHAR
*end
= name
+ lstrlenW(name
);
895 SIZE_T len
= end
- name
;
897 if (!(ret
= read_file( file
, &data
, &size
)))
903 if (end
> name
+ 2 && !wcsncmp( end
- 2, L
"16", 2 )) len
-= 2; /* remove "16" suffix */
904 memcpy( destname
, name
, len
* sizeof(WCHAR
) );
906 if (!add_handled_dll( destname
)) ret
= -1;
910 HANDLE h
= create_dest_file( dest
, delete );
912 if (h
&& h
!= INVALID_HANDLE_VALUE
)
914 TRACE( "%s -> %s\n", debugstr_w(file
), debugstr_w(dest
) );
916 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
917 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(dest
), GetLastError() );
919 if (ret
) register_fake_dll( dest
, data
, size
, delay_copy
);
920 else DeleteFileW( dest
);
923 *destname
= 0; /* restore it for next file */
928 static void delay_copy_files( struct list
*delay_copy
)
930 struct delay_copy
*copy
, *next
;
937 LIST_FOR_EACH_ENTRY_SAFE( copy
, next
, delay_copy
, struct delay_copy
, entry
)
939 list_remove( ©
->entry
);
940 ret
= read_file( copy
->src
, &data
, &size
);
943 HeapFree( GetProcessHeap(), 0, copy
);
947 h
= create_dest_file( copy
->dest
, FALSE
);
948 if (h
&& h
!= INVALID_HANDLE_VALUE
)
950 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
951 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(copy
->dest
), GetLastError() );
953 if (!ret
) DeleteFileW( copy
->dest
);
955 HeapFree( GetProcessHeap(), 0, copy
);
959 /* find and install all fake dlls in a given lib directory */
960 static void install_lib_dir( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*wildcard
,
961 const WCHAR
*default_ext
, BOOL
delete )
965 struct _wfinddata_t data
;
966 struct list delay_copy
= LIST_INIT( delay_copy
);
968 file
[1] = '\\'; /* change \??\ to \\?\ */
969 name
= file
+ lstrlenW(file
);
971 lstrcpyW( name
, wildcard
);
973 if ((handle
= _wfindfirst( file
, &data
)) == -1) return;
976 if (lstrlenW( data
.name
) > max_dll_name_len
) continue;
977 if (!wcscmp( data
.name
, L
"." )) continue;
978 if (!wcscmp( data
.name
, L
".." )) continue;
979 lstrcpyW( name
, data
.name
);
980 if (default_ext
) /* inside build dir */
982 lstrcatW( name
, L
"\\" );
983 lstrcatW( name
, data
.name
);
984 if (wcschr( data
.name
, '.' ) && install_fake_dll( dest
, file
, delete, &delay_copy
))
986 lstrcatW( name
, default_ext
);
988 install_fake_dll( dest
, file
, delete, &delay_copy
);
990 while (!_wfindnext( handle
, &data
));
991 _findclose( handle
);
993 delay_copy_files( &delay_copy
);
996 /* create fake dlls in dirname for all the files we can find */
997 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
, const WCHAR
*wildcard
, BOOL
delete )
999 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
1001 unsigned int i
, maxlen
= 0;
1002 WCHAR
*file
, *dest
, *p
;
1004 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + 1;
1005 for (i
= 0; (path
= enum_load_path(i
)); i
++) maxlen
= max( maxlen
, lstrlenW(path
) );
1006 maxlen
+= 2 * max_dll_name_len
+ 2 + ARRAY_SIZE(pe_dir
) + 10; /* ".dll" */
1007 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return FALSE
;
1009 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
1011 HeapFree( GetProcessHeap(), 0, file
);
1014 lstrcpyW( dest
, dirname
);
1015 if ((p
= wcsrchr( dest
, '\\' ))) p
[1] = 0; /* remove wildcard */
1019 lstrcpyW( file
, build_dir
);
1020 lstrcatW( file
, L
"\\dlls" );
1021 install_lib_dir( dest
, file
, wildcard
, L
".dll", delete );
1022 lstrcpyW( file
, build_dir
);
1023 lstrcatW( file
, L
"\\programs" );
1024 install_lib_dir( dest
, file
, wildcard
, L
".exe", delete );
1026 for (i
= 0; (path
= enum_load_path( i
)); i
++)
1028 swprintf( file
, maxlen
, L
"%s%s", path
, pe_dir
);
1029 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1030 lstrcpyW( file
, path
);
1031 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1033 HeapFree( GetProcessHeap(), 0, file
);
1034 HeapFree( GetProcessHeap(), 0, dest
);
1038 /***********************************************************************
1041 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
1043 struct list delay_copy
= LIST_INIT( delay_copy
);
1047 const WCHAR
*filename
;
1049 BOOL
delete = !wcscmp( source
, L
"-" ); /* '-' source means delete the file */
1051 if (!(filename
= wcsrchr( name
, '\\' ))) filename
= name
;
1054 /* check for empty name which means to only create the directory */
1057 create_directories( name
);
1060 if (wcspbrk( filename
, L
"*?" )) return create_wildcard_dlls( name
, filename
, delete );
1062 add_handled_dll( filename
);
1064 if (!(h
= create_dest_file( name
, delete ))) return TRUE
; /* not a fake dll */
1065 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
1067 if ((buffer
= load_fake_dll( source
, &size
)))
1071 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
1072 if (ret
) register_fake_dll( name
, buffer
, size
, &delay_copy
);
1073 else ERR( "failed to write to %s (error=%lu)\n", debugstr_w(name
), GetLastError() );
1077 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
1078 ret
= build_fake_dll( h
, name
);
1082 if (!ret
) DeleteFileW( name
);
1084 delay_copy_files( &delay_copy
);
1089 /***********************************************************************
1092 void cleanup_fake_dlls(void)
1094 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
1096 HeapFree( GetProcessHeap(), 0, handled_dlls
);
1097 handled_dlls
= NULL
;
1098 handled_count
= handled_total
= 0;
1099 if (registrar
) IRegistrar_Release( registrar
);