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 new_dlls
= realloc( handled_dlls
, new_count
* sizeof(*handled_dlls
) );
151 if (!new_dlls
) return FALSE
;
152 handled_dlls
= new_dlls
;
153 handled_total
= new_count
;
156 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
157 handled_dlls
[i
] = wcsdup( name
);
162 static int is_valid_ptr( const void *data
, SIZE_T size
, const void *ptr
, SIZE_T ptr_size
)
164 if (ptr
< data
) return 0;
165 if ((char *)ptr
- (char *)data
>= size
) return 0;
166 return (size
- ((char *)ptr
- (char *)data
) >= ptr_size
);
169 /* extract the 16-bit NE dll from a PE builtin */
170 static void extract_16bit_image( IMAGE_NT_HEADERS
*nt
, void **data
, SIZE_T
*size
)
172 DWORD exp_size
, *size_ptr
;
173 IMAGE_DOS_HEADER
*dos
;
174 IMAGE_EXPORT_DIRECTORY
*exports
;
175 IMAGE_SECTION_HEADER
*section
= NULL
;
177 DWORD
*names
, *functions
;
180 exports
= RtlImageDirectoryEntryToData( *data
, FALSE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
181 if (!is_valid_ptr( *data
, *size
, exports
, exp_size
)) return;
182 ordinals
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNameOrdinals
, §ion
);
183 names
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNames
, §ion
);
184 functions
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfFunctions
, §ion
);
185 if (!is_valid_ptr( *data
, *size
, ordinals
, exports
->NumberOfNames
* sizeof(*ordinals
) )) return;
186 if (!is_valid_ptr( *data
, *size
, names
, exports
->NumberOfNames
* sizeof(*names
) )) return;
188 for (i
= 0; i
< exports
->NumberOfNames
; i
++)
190 char *ename
= RtlImageRvaToVa( nt
, *data
, names
[i
], §ion
);
191 if (strcmp( ename
, "__wine_spec_dos_header" )) continue;
192 if (ordinals
[i
] >= exports
->NumberOfFunctions
) return;
193 if (!is_valid_ptr( *data
, *size
, functions
, sizeof(*functions
) )) return;
194 if (!functions
[ordinals
[i
]]) return;
195 dos
= RtlImageRvaToVa( nt
, *data
, functions
[ordinals
[i
]], NULL
);
196 if (!is_valid_ptr( *data
, *size
, dos
, sizeof(*dos
) )) return;
197 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return;
198 size_ptr
= (DWORD
*)dos
->e_res2
;
199 *size
= min( *size_ptr
, *size
- ((const char *)dos
- (const char *)*data
) );
206 /* read in the contents of a file into the global file buffer */
207 /* return 1 on success, 0 on nonexistent file, -1 on other error */
208 static int read_file( const WCHAR
*name
, void **data
, SIZE_T
*size
)
213 IMAGE_DOS_HEADER
*dos
;
214 IMAGE_NT_HEADERS
*nt
;
215 const size_t min_size
= sizeof(*dos
) + 32 +
216 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
218 if ((fd
= _wopen( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
219 if (fstat( fd
, &st
) == -1) goto done
;
221 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
223 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
225 file_buffer_size
= st
.st_size
;
226 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
227 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
230 /* check for valid fake dll file */
232 if (st
.st_size
< min_size
) goto done
;
233 header_size
= min( st
.st_size
, 4096 );
234 if (read( fd
, file_buffer
, header_size
) != header_size
) goto done
;
236 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
237 if (dos
->e_lfanew
< sizeof(*dos
) + 32) goto done
;
238 if (memcmp( dos
+ 1, builtin_signature
, strlen(builtin_signature
) + 1 ) &&
239 memcmp( dos
+ 1, fakedll_signature
, strlen(fakedll_signature
) + 1 )) goto done
;
240 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
242 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
243 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
245 /* wrong 32/64 type, pretend it doesn't exist */
249 if (st
.st_size
== header_size
||
250 read( fd
, (char *)file_buffer
+ header_size
,
251 st
.st_size
- header_size
) == st
.st_size
- header_size
)
254 if (lstrlenW(name
) > 2 && !wcscmp( name
+ lstrlenW(name
) - 2, L
"16" ))
255 extract_16bit_image( nt
, data
, size
);
263 /* build a complete fake dll from scratch */
264 static BOOL
build_fake_dll( HANDLE file
, const WCHAR
*name
)
266 IMAGE_DOS_HEADER
*dos
;
267 IMAGE_NT_HEADERS
*nt
;
268 struct dll_info info
;
272 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
273 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
276 buffer
= calloc( 1, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
278 dos
= (IMAGE_DOS_HEADER
*)buffer
;
279 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
280 dos
->e_cblp
= sizeof(*dos
);
282 dos
->e_cparhdr
= lfanew
/ 16;
284 dos
->e_maxalloc
= 0xffff;
287 dos
->e_lfarlc
= lfanew
;
288 dos
->e_lfanew
= lfanew
;
289 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
291 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
292 /* some fields are copied from the source dll */
293 #if defined __x86_64__
294 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
295 #elif defined __aarch64__
296 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARM64
;
297 #elif defined __arm__
298 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARMNT
;
300 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
302 nt
->FileHeader
.TimeDateStamp
= 0;
303 nt
->FileHeader
.Characteristics
= 0;
304 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
305 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
306 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
307 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
308 nt
->OptionalHeader
.MajorImageVersion
= 1;
309 nt
->OptionalHeader
.MinorImageVersion
= 0;
310 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
311 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
312 nt
->OptionalHeader
.Win32VersionValue
= 0;
313 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
314 nt
->OptionalHeader
.DllCharacteristics
= 0;
315 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
316 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
317 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
318 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
319 /* other fields have fixed values */
320 nt
->Signature
= IMAGE_NT_SIGNATURE
;
321 nt
->FileHeader
.NumberOfSections
= 0;
322 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
323 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
324 nt
->OptionalHeader
.ImageBase
= 0x10000000;
325 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
326 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
327 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
329 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
330 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
331 info
.file_pos
= ALIGN( header_size
, file_alignment
);
333 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
334 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
336 ext
= wcsrchr( name
, '.' );
337 if (!ext
|| wcsicmp( ext
, L
".exe" )) nt
->FileHeader
.Characteristics
|= IMAGE_FILE_DLL
;
339 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
341 size
= sizeof(dll_code_section
);
342 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
346 size
= sizeof(exe_code_section
);
347 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
349 nt
->OptionalHeader
.SizeOfCode
= size
;
350 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
352 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
353 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
354 add_section( &info
, ".reloc", sizeof(reloc_section
),
355 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
357 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
358 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
359 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
360 ret
= xwrite( &info
, buffer
, header_size
, 0 );
366 /* check if an existing file is a fake dll so that we can overwrite it */
367 static BOOL
is_fake_dll( HANDLE h
)
369 IMAGE_DOS_HEADER
*dos
;
371 BYTE buffer
[sizeof(*dos
) + 32];
373 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
375 dos
= (IMAGE_DOS_HEADER
*)buffer
;
376 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
377 if (dos
->e_lfanew
< size
) return FALSE
;
378 return (!memcmp( dos
+ 1, builtin_signature
, sizeof(builtin_signature
) ) ||
379 !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) ));
382 /* create directories leading to a given file */
383 static void create_directories( const WCHAR
*name
)
387 /* create the directory/directories */
388 path
= malloc((wcslen(name
) + 1) * sizeof(WCHAR
));
389 lstrcpyW(path
, name
);
391 p
= wcschr(path
, '\\');
395 if (!CreateDirectoryW(path
, NULL
))
396 TRACE("Couldn't create directory %s - error: %ld\n", wine_dbgstr_w(path
), GetLastError());
398 p
= wcschr(p
+1, '\\');
403 static inline WCHAR
*prepend( WCHAR
*buffer
, const WCHAR
*str
, size_t len
)
405 return memcpy( buffer
- len
, str
, len
* sizeof(WCHAR
) );
408 static inline WCHAR
*prepend_build_dir_path( WCHAR
*ptr
, const WCHAR
*ext
, const WCHAR
*arch_dir
,
409 const WCHAR
*top_dir
, const WCHAR
*build_dir
)
412 unsigned int namelen
= wcslen(name
), extlen
= wcslen(ext
);
414 if (namelen
> extlen
&& !wcscmp( name
+ namelen
- extlen
, ext
)) namelen
-= extlen
;
415 ptr
= prepend( ptr
, arch_dir
, wcslen(arch_dir
) );
416 ptr
= prepend( ptr
, name
, namelen
);
417 ptr
= prepend( ptr
, top_dir
, wcslen(top_dir
) );
418 ptr
= prepend( ptr
, build_dir
, wcslen(build_dir
) );
423 static const WCHAR
*enum_load_path( unsigned int idx
)
426 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"WINEDLLDIR%u", idx
);
427 return _wgetenv( buffer
);
430 /* try to load a pre-compiled fake dll */
431 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
433 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
437 unsigned int i
, pos
, len
, maxlen
= 0;
441 if ((p
= wcsrchr( name
, '\\' ))) name
= p
+ 1;
444 len
= lstrlenW( name
);
445 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + len
+ 1;
446 while ((path
= enum_load_path( i
++ ))) maxlen
= max( maxlen
, lstrlenW(path
) );
447 maxlen
+= ARRAY_SIZE(pe_dir
) + len
+ 1;
449 if (!(file
= malloc( maxlen
* sizeof(WCHAR
) ))) return NULL
;
451 pos
= maxlen
- len
- 1;
452 lstrcpyW( file
+ pos
, name
);
458 file
[pos
+ len
+ 1] = 0;
459 ptr
= prepend_build_dir_path( file
+ pos
, L
".dll", pe_dir
, L
"\\dlls", build_dir
);
460 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
462 /* now as a program */
463 file
[pos
+ len
+ 1] = 0;
464 ptr
= prepend_build_dir_path( file
+ pos
, L
".exe", pe_dir
, L
"\\programs", build_dir
);
465 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
468 file
[pos
+ len
+ 1] = 0;
469 for (i
= 0; (path
= enum_load_path( i
)); i
++)
471 ptr
= prepend( file
+ pos
, pe_dir
, lstrlenW(pe_dir
) );
472 ptr
= prepend( ptr
, path
, lstrlenW(path
) );
473 if ((res
= read_file( ptr
, &data
, size
))) break;
474 ptr
= prepend( file
+ pos
, path
, lstrlenW(path
) );
475 if ((res
= read_file( ptr
, &data
, size
))) break;
480 if (res
== 1) return data
;
484 /* create the fake dll destination file */
485 static HANDLE
create_dest_file( const WCHAR
*name
, BOOL
delete )
487 /* first check for an existing file */
488 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
489 if (h
!= INVALID_HANDLE_VALUE
)
491 if (!is_fake_dll( h
))
493 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
501 return INVALID_HANDLE_VALUE
;
503 /* truncate the file */
504 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
509 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
511 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
512 if (h
== INVALID_HANDLE_VALUE
)
513 ERR( "failed to create %s (error=%lu)\n", debugstr_w(name
), GetLastError() );
518 /* XML parsing code copied from ntdll */
532 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
534 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
537 static inline BOOL
isxmlspace( char ch
)
539 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
542 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
548 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
551 xmlbuf
->ptr
= xmlbuf
->end
;
555 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
557 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
558 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
560 if (ptr
+ 3 > xmlbuf
->end
)
562 xmlbuf
->ptr
= xmlbuf
->end
;
565 xmlbuf
->ptr
= ptr
+ 3;
571 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
574 elem
->ptr
= xmlbuf
->ptr
;
575 elem
->len
= ptr
- xmlbuf
->ptr
;
577 return xmlbuf
->ptr
!= xmlbuf
->end
;
580 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
, BOOL
* error
)
586 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
589 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
591 if (*xmlbuf
->ptr
== '/')
594 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
602 if (*xmlbuf
->ptr
== '>')
610 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
612 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
614 name
->ptr
= xmlbuf
->ptr
;
615 name
->len
= ptr
-xmlbuf
->ptr
;
619 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
622 if (ptr
== xmlbuf
->end
) return FALSE
;
624 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
627 xmlbuf
->ptr
= xmlbuf
->end
;
631 value
->len
= ptr
- value
->ptr
;
632 xmlbuf
->ptr
= ptr
+ 1;
634 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
640 static void append_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
641 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
643 DWORD pos
= lstrlenW( buffer
);
645 pos
+= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
+ pos
, size
- pos
);
647 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
649 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
651 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
653 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
654 lstrcpyW( buffer
+ pos
, L
"_deadbeef" );
658 static WCHAR
* create_winsxs_dll_path( const xmlstr_t
*arch
, const xmlstr_t
*name
,
659 const xmlstr_t
*key
, const xmlstr_t
*version
,
660 const xmlstr_t
*lang
)
665 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\" )
666 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 19;
668 path
= malloc( path_len
* sizeof(WCHAR
) );
669 GetWindowsDirectoryW( path
, path_len
);
670 lstrcatW( path
, L
"\\winsxs\\" );
671 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
672 lstrcatW( path
, L
"\\" );
676 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
677 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
680 DWORD written
, path_len
;
684 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\manifests\\" )
685 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + ARRAY_SIZE( L
".manifest" );
687 path
= malloc( path_len
* sizeof(WCHAR
) );
688 GetWindowsDirectoryW( path
, path_len
);
689 lstrcatW( path
, L
"\\winsxs\\manifests\\" );
690 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
691 lstrcatW( path
, L
".manifest" );
692 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
693 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
695 create_directories( path
);
696 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
699 if (handle
!= INVALID_HANDLE_VALUE
)
701 TRACE( "creating %s\n", debugstr_w(path
) );
702 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
703 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(path
), GetLastError() );
704 CloseHandle( handle
);
705 if (!ret
) DeleteFileW( path
);
721 struct list
*delay_copy
;
722 const WCHAR
*src_dir
;
726 static BOOL CALLBACK
register_manifest( HMODULE module
, const WCHAR
*type
, WCHAR
*res_name
, LONG_PTR arg
)
728 const struct dll_data
*dll_data
= (const struct dll_data
*)arg
;
732 xmlstr_t elem
, attr_name
, attr_value
;
733 xmlstr_t name
, version
, arch
, key
, lang
;
735 const char *manifest
;
739 if (IS_INTRESOURCE( res_name
) || wcsncmp( res_name
, L
"WINE_MANIFEST", 13 )) return TRUE
;
741 rsrc
= FindResourceW( module
, res_name
, type
);
742 manifest
= LoadResource( module
, rsrc
);
743 len
= SizeofResource( module
, rsrc
);
745 buffer
.ptr
= manifest
;
746 buffer
.end
= manifest
+ len
;
747 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
748 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
750 while (next_xml_elem( &buffer
, &elem
))
752 if (xmlstr_cmp( &elem
, "file" ))
754 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
756 if (xmlstr_cmp(&attr_name
, "name"))
763 if (!error
&& dest
&& name
.ptr
)
765 struct delay_copy
*add
= malloc( sizeof(*add
) +
766 (dll_data
->src_len
+ name
.len
+ dest_len
+ name
.len
+ 1) * sizeof(WCHAR
) );
767 add
->src
= add
->data
;
768 memcpy( add
->src
, dll_data
->src_dir
, dll_data
->src_len
* sizeof(WCHAR
) );
769 MultiByteToWideChar( CP_UTF8
, 0, name
.ptr
, name
.len
,
770 add
->src
+ dll_data
->src_len
, name
.len
);
771 add
->src
[dll_data
->src_len
+ name
.len
] = 0;
772 add
->dest
= add
->data
+ dll_data
->src_len
+ name
.len
+ 1;
773 memcpy( add
->dest
, dest
, dest_len
* sizeof(WCHAR
) );
774 memcpy( add
->dest
+ dest_len
, add
->src
+ dll_data
->src_len
,
775 (name
.len
+ 1) * sizeof(WCHAR
) );
776 TRACE("schedule copy %s -> %s\n", wine_dbgstr_w(add
->src
), wine_dbgstr_w(add
->dest
));
777 list_add_tail( dll_data
->delay_copy
, &add
->entry
);
782 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
785 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
787 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
788 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
789 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
790 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
791 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
793 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
798 lang
.len
= strlen( lang
.ptr
);
800 if (!arch
.len
) /* fixup the architecture */
802 char *new_buffer
= malloc( len
+ sizeof(current_arch
) );
803 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
804 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
805 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
806 arch
.ptr
= current_arch
;
807 arch
.len
= strlen( current_arch
);
808 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
809 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
814 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
815 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
817 dest_len
= wcslen( dest
);
825 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
827 HRESULT
*hr
= (HRESULT
*)arg
;
829 HRSRC rsrc
= FindResourceW( module
, name
, type
);
830 char *str
= LoadResource( module
, rsrc
);
831 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
833 if (!str
) return FALSE
;
834 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
835 if (!(buffer
= malloc( lenW
* sizeof(WCHAR
) ))) return FALSE
;
836 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
837 buffer
[lenW
- 1] = 0;
838 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
843 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
, struct list
*delay_copy
)
845 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
846 LDR_RESOURCE_INFO info
;
848 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
849 struct dll_data dll_data
= { delay_copy
, name
, 0 };
850 WCHAR buffer
[MAX_PATH
];
853 if (!(p
= wcsrchr( name
, '\\' ))) p
= name
;
855 dll_data
.src_len
= p
- name
;
856 EnumResourceNamesW( module
, (WCHAR
*)RT_MANIFEST
, register_manifest
, (LONG_PTR
)&dll_data
);
858 info
.Type
= (ULONG_PTR
)L
"WINE_REGISTRY";
859 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
863 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
864 HMODULE atl
= LoadLibraryW( L
"atl100.dll" );
866 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
867 hr
= pAtlCreateRegistrar( ®istrar
);
873 ERR( "failed to create IRegistrar: %lx\n", hr
);
878 TRACE( "registering %s\n", debugstr_w(name
) );
879 IRegistrar_ClearReplacements( registrar
);
880 IRegistrar_AddReplacement( registrar
, L
"MODULE", name
);
881 GetEnvironmentVariableW( L
"SystemRoot", buffer
, ARRAY_SIZE(buffer
) );
882 IRegistrar_AddReplacement( registrar
, L
"SystemRoot", buffer
);
883 EnumResourceNamesW( module
, L
"WINE_REGISTRY", register_resource
, (LONG_PTR
)&hr
);
884 if (FAILED(hr
)) ERR( "failed to register %s: %lx\n", debugstr_w(name
), hr
);
887 /* copy a fake dll file to the dest directory */
888 static int install_fake_dll( WCHAR
*dest
, WCHAR
*file
, BOOL
delete, struct list
*delay_copy
)
894 WCHAR
*destname
= dest
+ lstrlenW(dest
);
895 WCHAR
*name
= wcsrchr( file
, '\\' ) + 1;
896 WCHAR
*end
= name
+ lstrlenW(name
);
897 SIZE_T len
= end
- name
;
899 if (!(ret
= read_file( file
, &data
, &size
)))
905 if (end
> name
+ 2 && !wcsncmp( end
- 2, L
"16", 2 )) len
-= 2; /* remove "16" suffix */
906 memcpy( destname
, name
, len
* sizeof(WCHAR
) );
908 if (!add_handled_dll( destname
)) ret
= -1;
912 HANDLE h
= create_dest_file( dest
, delete );
914 if (h
&& h
!= INVALID_HANDLE_VALUE
)
916 TRACE( "%s -> %s\n", debugstr_w(file
), debugstr_w(dest
) );
918 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
919 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(dest
), GetLastError() );
921 if (ret
) register_fake_dll( dest
, data
, size
, delay_copy
);
922 else DeleteFileW( dest
);
925 *destname
= 0; /* restore it for next file */
930 static void delay_copy_files( struct list
*delay_copy
)
932 struct delay_copy
*copy
, *next
;
939 LIST_FOR_EACH_ENTRY_SAFE( copy
, next
, delay_copy
, struct delay_copy
, entry
)
941 list_remove( ©
->entry
);
942 ret
= read_file( copy
->src
, &data
, &size
);
949 h
= create_dest_file( copy
->dest
, FALSE
);
950 if (h
&& h
!= INVALID_HANDLE_VALUE
)
952 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
953 if (!ret
) ERR( "failed to write to %s (error=%lu)\n", debugstr_w(copy
->dest
), GetLastError() );
955 if (!ret
) DeleteFileW( copy
->dest
);
961 /* find and install all fake dlls in a given lib directory */
962 static void install_lib_dir( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*wildcard
,
963 const WCHAR
*default_ext
, BOOL
delete )
967 struct _wfinddata_t data
;
968 struct list delay_copy
= LIST_INIT( delay_copy
);
970 file
[1] = '\\'; /* change \??\ to \\?\ */
971 name
= file
+ lstrlenW(file
);
973 lstrcpyW( name
, wildcard
);
975 if ((handle
= _wfindfirst( file
, &data
)) == -1) return;
978 if (lstrlenW( data
.name
) > max_dll_name_len
) continue;
979 if (!wcscmp( data
.name
, L
"." )) continue;
980 if (!wcscmp( data
.name
, L
".." )) continue;
981 lstrcpyW( name
, data
.name
);
982 if (default_ext
) /* inside build dir */
984 lstrcatW( name
, pe_dir
);
985 lstrcatW( name
, L
"\\" );
986 lstrcatW( name
, data
.name
);
987 if (wcschr( data
.name
, '.' ) && install_fake_dll( dest
, file
, delete, &delay_copy
))
989 if (wcschr( wildcard
, '.' )) /* don't append default if wildcard has an explicit extension */
991 lstrcatW( name
, default_ext
);
993 install_fake_dll( dest
, file
, delete, &delay_copy
);
995 while (!_wfindnext( handle
, &data
));
996 _findclose( handle
);
998 delay_copy_files( &delay_copy
);
1001 /* create fake dlls in dirname for all the files we can find */
1002 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
, const WCHAR
*wildcard
, BOOL
delete )
1004 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
1006 unsigned int i
, maxlen
= 0;
1007 WCHAR
*file
, *dest
, *p
;
1009 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + 1;
1010 for (i
= 0; (path
= enum_load_path(i
)); i
++) maxlen
= max( maxlen
, lstrlenW(path
) );
1011 maxlen
+= 2 * max_dll_name_len
+ 2 + ARRAY_SIZE(pe_dir
) + 10; /* ".dll" */
1012 if (!(file
= malloc( maxlen
* sizeof(WCHAR
) ))) return FALSE
;
1014 if (!(dest
= malloc( (wcslen(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
1019 lstrcpyW( dest
, dirname
);
1020 if ((p
= wcsrchr( dest
, '\\' ))) p
[1] = 0; /* remove wildcard */
1024 lstrcpyW( file
, build_dir
);
1025 lstrcatW( file
, L
"\\dlls" );
1026 install_lib_dir( dest
, file
, wildcard
, L
".dll", delete );
1027 lstrcpyW( file
, build_dir
);
1028 lstrcatW( file
, L
"\\programs" );
1029 install_lib_dir( dest
, file
, wildcard
, L
".exe", delete );
1031 for (i
= 0; (path
= enum_load_path( i
)); i
++)
1033 swprintf( file
, maxlen
, L
"%s%s", path
, pe_dir
);
1034 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1035 lstrcpyW( file
, path
);
1036 install_lib_dir( dest
, file
, wildcard
, NULL
, delete );
1043 /***********************************************************************
1046 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
1048 struct list delay_copy
= LIST_INIT( delay_copy
);
1052 const WCHAR
*filename
;
1054 BOOL
delete = !wcscmp( source
, L
"-" ); /* '-' source means delete the file */
1056 if (!(filename
= wcsrchr( name
, '\\' ))) filename
= name
;
1059 /* check for empty name which means to only create the directory */
1062 create_directories( name
);
1065 if (wcspbrk( filename
, L
"*?" )) return create_wildcard_dlls( name
, filename
, delete );
1067 add_handled_dll( filename
);
1069 if (!(h
= create_dest_file( name
, delete ))) return TRUE
; /* not a fake dll */
1070 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
1072 if ((buffer
= load_fake_dll( source
, &size
)))
1076 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
1077 if (ret
) register_fake_dll( name
, buffer
, size
, &delay_copy
);
1078 else ERR( "failed to write to %s (error=%lu)\n", debugstr_w(name
), GetLastError() );
1082 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
1083 ret
= build_fake_dll( h
, name
);
1087 if (!ret
) DeleteFileW( name
);
1089 delay_copy_files( &delay_copy
);
1094 /***********************************************************************
1097 void cleanup_fake_dlls(void)
1099 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
1101 free( handled_dlls
);
1102 handled_dlls
= NULL
;
1103 handled_count
= handled_total
= 0;
1104 if (registrar
) IRegistrar_Release( registrar
);