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: %d\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
+ ARRAY_SIZE(L
".fake");
436 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return NULL
;
438 pos
= maxlen
- len
- ARRAY_SIZE(L
".fake");
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
;
453 lstrcpyW( file
+ pos
+ len
+ 1, L
".fake" );
454 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
456 /* now as a program */
459 file
[pos
+ len
+ 1] = 0;
460 if (namelen
> 4 && !wcsncmp( ptr
+ namelen
- 4, L
".exe", 4 )) namelen
-= 4;
461 ptr
= prepend( ptr
, ptr
, namelen
);
462 ptr
= prepend( ptr
, L
"\\programs", 9 );
463 ptr
= prepend( ptr
, build_dir
, lstrlenW(build_dir
) );
464 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
465 lstrcpyW( file
+ pos
+ len
+ 1, L
".fake" );
466 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
469 file
[pos
+ len
+ 1] = 0;
470 for (i
= 0; (path
= enum_load_path( i
)); i
++)
472 ptr
= prepend( file
+ pos
, pe_dir
, lstrlenW(pe_dir
) );
473 ptr
= prepend( ptr
, path
, lstrlenW(path
) );
474 if ((res
= read_file( ptr
, &data
, size
))) break;
475 ptr
= prepend( file
+ pos
, path
, lstrlenW(path
) );
476 if ((res
= read_file( ptr
, &data
, size
))) break;
480 HeapFree( GetProcessHeap(), 0, file
);
481 if (res
== 1) return data
;
485 /* create the fake dll destination file */
486 static HANDLE
create_dest_file( const WCHAR
*name
, BOOL
delete )
488 /* first check for an existing file */
489 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
490 if (h
!= INVALID_HANDLE_VALUE
)
492 if (!is_fake_dll( h
))
494 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
502 return INVALID_HANDLE_VALUE
;
504 /* truncate the file */
505 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
510 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
512 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
513 if (h
== INVALID_HANDLE_VALUE
)
514 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
519 /* XML parsing code copied from ntdll */
533 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
535 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
538 static inline BOOL
isxmlspace( char ch
)
540 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
543 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
549 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
552 xmlbuf
->ptr
= xmlbuf
->end
;
556 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
558 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
559 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
561 if (ptr
+ 3 > xmlbuf
->end
)
563 xmlbuf
->ptr
= xmlbuf
->end
;
566 xmlbuf
->ptr
= ptr
+ 3;
572 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
575 elem
->ptr
= xmlbuf
->ptr
;
576 elem
->len
= ptr
- xmlbuf
->ptr
;
578 return xmlbuf
->ptr
!= xmlbuf
->end
;
581 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
, BOOL
* error
)
587 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
590 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
592 if (*xmlbuf
->ptr
== '/')
595 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
603 if (*xmlbuf
->ptr
== '>')
611 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
613 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
615 name
->ptr
= xmlbuf
->ptr
;
616 name
->len
= ptr
-xmlbuf
->ptr
;
620 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
623 if (ptr
== xmlbuf
->end
) return FALSE
;
625 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
628 xmlbuf
->ptr
= xmlbuf
->end
;
632 value
->len
= ptr
- value
->ptr
;
633 xmlbuf
->ptr
= ptr
+ 1;
635 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
641 static void append_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
642 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
644 DWORD pos
= lstrlenW( buffer
);
646 pos
+= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
+ pos
, size
- pos
);
648 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
650 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
652 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
654 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
655 lstrcpyW( buffer
+ pos
, L
"_deadbeef" );
659 static WCHAR
* create_winsxs_dll_path( const xmlstr_t
*arch
, const xmlstr_t
*name
,
660 const xmlstr_t
*key
, const xmlstr_t
*version
,
661 const xmlstr_t
*lang
)
666 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\" )
667 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 19;
669 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
670 GetWindowsDirectoryW( path
, path_len
);
671 lstrcatW( path
, L
"\\winsxs\\" );
672 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
673 lstrcatW( path
, L
"\\" );
677 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
678 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
681 DWORD written
, path_len
;
685 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\manifests\\" )
686 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + ARRAY_SIZE( L
".manifest" );
688 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
689 GetWindowsDirectoryW( path
, path_len
);
690 lstrcatW( path
, L
"\\winsxs\\manifests\\" );
691 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
692 lstrcatW( path
, L
".manifest" );
693 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
694 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
696 create_directories( path
);
697 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
700 if (handle
!= INVALID_HANDLE_VALUE
)
702 TRACE( "creating %s\n", debugstr_w(path
) );
703 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
704 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
705 CloseHandle( handle
);
706 if (!ret
) DeleteFileW( path
);
708 HeapFree( GetProcessHeap(), 0, path
);
722 struct list
*delay_copy
;
723 const WCHAR
*src_dir
;
727 static BOOL CALLBACK
register_manifest( HMODULE module
, const WCHAR
*type
, WCHAR
*res_name
, LONG_PTR arg
)
729 const struct dll_data
*dll_data
= (const struct dll_data
*)arg
;
733 xmlstr_t elem
, attr_name
, attr_value
;
734 xmlstr_t name
, version
, arch
, key
, lang
;
736 const char *manifest
;
740 if (IS_INTRESOURCE( res_name
) || wcsncmp( res_name
, L
"WINE_MANIFEST", 13 )) return TRUE
;
742 rsrc
= FindResourceW( module
, res_name
, type
);
743 manifest
= LoadResource( module
, rsrc
);
744 len
= SizeofResource( module
, rsrc
);
746 buffer
.ptr
= manifest
;
747 buffer
.end
= manifest
+ len
;
748 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
749 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
751 while (next_xml_elem( &buffer
, &elem
))
753 if (xmlstr_cmp( &elem
, "file" ))
755 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
757 if (xmlstr_cmp(&attr_name
, "name"))
764 if (!error
&& dest
&& name
.ptr
)
766 struct delay_copy
*add
= HeapAlloc( GetProcessHeap(), 0,
767 sizeof(*add
) + (dll_data
->src_len
+ name
.len
+
768 dest_len
+ name
.len
+ 1) * sizeof(WCHAR
) );
769 add
->src
= add
->data
;
770 memcpy( add
->src
, dll_data
->src_dir
, dll_data
->src_len
* sizeof(WCHAR
) );
771 MultiByteToWideChar( CP_UTF8
, 0, name
.ptr
, name
.len
,
772 add
->src
+ dll_data
->src_len
, name
.len
);
773 add
->src
[dll_data
->src_len
+ name
.len
] = 0;
774 add
->dest
= add
->data
+ dll_data
->src_len
+ name
.len
+ 1;
775 memcpy( add
->dest
, dest
, dest_len
* sizeof(WCHAR
) );
776 memcpy( add
->dest
+ dest_len
, add
->src
+ dll_data
->src_len
,
777 (name
.len
+ 1) * sizeof(WCHAR
) );
778 TRACE("schedule copy %s -> %s\n", wine_dbgstr_w(add
->src
), wine_dbgstr_w(add
->dest
));
779 list_add_tail( dll_data
->delay_copy
, &add
->entry
);
784 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
785 HeapFree( GetProcessHeap(), 0, dest
);
787 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
789 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
790 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
791 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
792 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
793 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
795 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
800 lang
.len
= strlen( lang
.ptr
);
802 if (!arch
.len
) /* fixup the architecture */
804 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
805 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
806 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
807 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
808 arch
.ptr
= current_arch
;
809 arch
.len
= strlen( current_arch
);
810 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
811 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
812 HeapFree( GetProcessHeap(), 0, new_buffer
);
816 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
817 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
819 dest_len
= wcslen( dest
);
822 HeapFree( GetProcessHeap(), 0, dest
);
827 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
829 HRESULT
*hr
= (HRESULT
*)arg
;
831 HRSRC rsrc
= FindResourceW( module
, name
, type
);
832 char *str
= LoadResource( module
, rsrc
);
833 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
835 if (!str
) return FALSE
;
836 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
837 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
838 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
839 buffer
[lenW
- 1] = 0;
840 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
841 HeapFree( GetProcessHeap(), 0, buffer
);
845 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
, struct list
*delay_copy
)
847 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
848 LDR_RESOURCE_INFO info
;
850 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
851 struct dll_data dll_data
= { delay_copy
, name
, 0 };
852 WCHAR buffer
[MAX_PATH
];
855 if (!(p
= wcsrchr( name
, '\\' ))) p
= name
;
857 dll_data
.src_len
= p
- name
;
858 EnumResourceNamesW( module
, (WCHAR
*)RT_MANIFEST
, register_manifest
, (LONG_PTR
)&dll_data
);
860 info
.Type
= (ULONG_PTR
)L
"WINE_REGISTRY";
861 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
865 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
866 HMODULE atl
= LoadLibraryW( L
"atl100.dll" );
868 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
869 hr
= pAtlCreateRegistrar( ®istrar
);
875 ERR( "failed to create IRegistrar: %x\n", hr
);
880 TRACE( "registering %s\n", debugstr_w(name
) );
881 IRegistrar_ClearReplacements( registrar
);
882 IRegistrar_AddReplacement( registrar
, L
"MODULE", name
);
883 GetEnvironmentVariableW( L
"SystemRoot", buffer
, ARRAY_SIZE(buffer
) );
884 IRegistrar_AddReplacement( registrar
, L
"SystemRoot", buffer
);
885 EnumResourceNamesW( module
, L
"WINE_REGISTRY", register_resource
, (LONG_PTR
)&hr
);
886 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
889 /* copy a fake dll file to the dest directory */
890 static int install_fake_dll( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*ext
, BOOL
delete, struct list
*delay_copy
)
896 WCHAR
*destname
= dest
+ lstrlenW(dest
);
897 WCHAR
*name
= wcsrchr( file
, '\\' ) + 1;
898 WCHAR
*end
= name
+ lstrlenW(name
);
899 SIZE_T len
= end
- name
;
901 if (ext
) lstrcpyW( end
, ext
);
902 if (!(ret
= read_file( file
, &data
, &size
)))
908 if (end
> name
+ 2 && !wcsncmp( end
- 2, L
"16", 2 )) len
-= 2; /* remove "16" suffix */
909 memcpy( destname
, name
, len
* sizeof(WCHAR
) );
911 if (!add_handled_dll( destname
)) ret
= -1;
915 HANDLE h
= create_dest_file( dest
, delete );
917 if (h
&& h
!= INVALID_HANDLE_VALUE
)
919 TRACE( "%s -> %s\n", debugstr_w(file
), debugstr_w(dest
) );
921 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
922 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
924 if (ret
) register_fake_dll( dest
, data
, size
, delay_copy
);
925 else DeleteFileW( dest
);
928 *destname
= 0; /* restore it for next file */
933 static void delay_copy_files( struct list
*delay_copy
)
935 struct delay_copy
*copy
, *next
;
942 LIST_FOR_EACH_ENTRY_SAFE( copy
, next
, delay_copy
, struct delay_copy
, entry
)
944 list_remove( ©
->entry
);
945 ret
= read_file( copy
->src
, &data
, &size
);
948 HeapFree( GetProcessHeap(), 0, copy
);
952 h
= create_dest_file( copy
->dest
, FALSE
);
953 if (h
&& h
!= INVALID_HANDLE_VALUE
)
955 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
956 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(copy
->dest
), GetLastError() );
958 if (!ret
) DeleteFileW( copy
->dest
);
960 HeapFree( GetProcessHeap(), 0, copy
);
964 /* find and install all fake dlls in a given lib directory */
965 static void install_lib_dir( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*wildcard
,
966 const WCHAR
*default_ext
, BOOL
delete )
970 struct _wfinddata_t data
;
971 struct list delay_copy
= LIST_INIT( delay_copy
);
973 file
[1] = '\\'; /* change \??\ to \\?\ */
974 name
= file
+ lstrlenW(file
);
976 lstrcpyW( name
, wildcard
);
978 if ((handle
= _wfindfirst( file
, &data
)) == -1) return;
981 if (lstrlenW( data
.name
) > max_dll_name_len
) continue;
982 if (!wcscmp( data
.name
, L
"." )) continue;
983 if (!wcscmp( data
.name
, L
".." )) continue;
984 lstrcpyW( name
, data
.name
);
985 if (default_ext
) /* inside build dir */
987 lstrcatW( name
, L
"\\" );
988 lstrcatW( name
, data
.name
);
989 if (wcschr( data
.name
, '.' )) /* module possibly already has an extension */
991 if (install_fake_dll( dest
, file
, NULL
, delete, &delay_copy
)) continue;
992 if (install_fake_dll( dest
, file
, L
".fake", delete, &delay_copy
)) continue;
994 lstrcatW( name
, default_ext
);
995 if (install_fake_dll( dest
, file
, NULL
, delete, &delay_copy
)) continue;
996 if (install_fake_dll( dest
, file
, L
".fake", delete, &delay_copy
)) continue;
998 else install_fake_dll( dest
, file
, NULL
, delete, &delay_copy
);
1000 while (!_wfindnext( handle
, &data
));
1001 _findclose( handle
);
1003 delay_copy_files( &delay_copy
);
1006 /* create fake dlls in dirname for all the files we can find */
1007 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
, const WCHAR
*wildcard
, BOOL
delete )
1009 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
1011 unsigned int i
, maxlen
= 0;
1012 WCHAR
*file
, *dest
, *p
;
1014 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + 1;
1015 for (i
= 0; (path
= enum_load_path(i
)); i
++) maxlen
= max( maxlen
, lstrlenW(path
) );
1016 maxlen
+= 2 * max_dll_name_len
+ 2 + ARRAY_SIZE(pe_dir
) + 10; /* ".dll.fake" */
1017 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return FALSE
;
1019 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
1021 HeapFree( GetProcessHeap(), 0, file
);
1024 lstrcpyW( dest
, dirname
);
1025 if ((p
= wcsrchr( dest
, '\\' ))) p
[1] = 0; /* remove wildcard */
1029 lstrcpyW( file
, build_dir
);
1030 lstrcatW( file
, L
"\\dlls" );
1031 install_lib_dir( dest
, file
, wildcard
, L
".dll", delete );
1032 lstrcpyW( file
, build_dir
);
1033 lstrcatW( file
, L
"\\programs" );
1034 install_lib_dir( dest
, file
, wildcard
, L
".exe", delete );
1036 for (i
= 0; (path
= enum_load_path( i
)); i
++)
1038 swprintf( file
, maxlen
, L
"%s%s", path
, pe_dir
);
1039 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1040 lstrcpyW( file
, path
);
1041 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1043 HeapFree( GetProcessHeap(), 0, file
);
1044 HeapFree( GetProcessHeap(), 0, dest
);
1048 /***********************************************************************
1051 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
1053 struct list delay_copy
= LIST_INIT( delay_copy
);
1057 const WCHAR
*filename
;
1059 BOOL
delete = !wcscmp( source
, L
"-" ); /* '-' source means delete the file */
1061 if (!(filename
= wcsrchr( name
, '\\' ))) filename
= name
;
1064 /* check for empty name which means to only create the directory */
1067 create_directories( name
);
1070 if (wcspbrk( filename
, L
"*?" )) return create_wildcard_dlls( name
, filename
, delete );
1072 add_handled_dll( filename
);
1074 if (!(h
= create_dest_file( name
, delete ))) return TRUE
; /* not a fake dll */
1075 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
1077 if ((buffer
= load_fake_dll( source
, &size
)))
1081 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
1082 if (ret
) register_fake_dll( name
, buffer
, size
, &delay_copy
);
1083 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
1087 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
1088 ret
= build_fake_dll( h
, name
);
1092 if (!ret
) DeleteFileW( name
);
1094 delay_copy_files( &delay_copy
);
1099 /***********************************************************************
1102 void cleanup_fake_dlls(void)
1104 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
1106 HeapFree( GetProcessHeap(), 0, handled_dlls
);
1107 handled_dlls
= NULL
;
1108 handled_count
= handled_total
= 0;
1109 if (registrar
) IRegistrar_Release( registrar
);