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
);
43 static const char builtin_signature
[] = "Wine builtin DLL";
44 static const char fakedll_signature
[] = "Wine placeholder DLL";
46 static const unsigned int file_alignment
= 512;
47 static const unsigned int section_alignment
= 4096;
48 static const unsigned int max_dll_name_len
= 64;
50 static void *file_buffer
;
51 static SIZE_T file_buffer_size
;
52 static unsigned int handled_count
;
53 static unsigned int handled_total
;
54 static WCHAR
**handled_dlls
;
55 static IRegistrar
*registrar
;
65 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
67 /* contents of the dll sections */
69 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
70 0xc2, 0x0c, 0x00 }; /* ret $12 */
72 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
73 0xc2, 0x04, 0x00 }; /* ret $4 */
75 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
78 /* wrapper for WriteFile */
79 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
83 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
84 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
88 /* add a new section to the dll NT header */
89 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
91 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
93 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
94 memcpy( sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
95 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
96 sec
->VirtualAddress
= info
->mem_pos
;
97 sec
->SizeOfRawData
= size
;
98 sec
->PointerToRawData
= info
->file_pos
;
99 sec
->Characteristics
= flags
;
100 info
->file_pos
+= ALIGN( size
, file_alignment
);
101 info
->mem_pos
+= ALIGN( size
, section_alignment
);
102 info
->nt
->FileHeader
.NumberOfSections
++;
105 /* add a data directory to the dll NT header */
106 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
108 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
109 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
112 /* add a dll to the list of dll that have been taken care of */
113 static BOOL
add_handled_dll( const WCHAR
*name
)
115 int i
, min
, max
, pos
, res
;
118 max
= handled_count
- 1;
121 pos
= (min
+ max
) / 2;
122 res
= wcscmp( handled_dlls
[pos
], name
);
123 if (!res
) return FALSE
; /* already in the list */
124 if (res
< 0) min
= pos
+ 1;
128 if (handled_count
>= handled_total
)
131 unsigned int new_count
= max( 64, handled_total
* 2 );
133 if (handled_dlls
) new_dlls
= HeapReAlloc( GetProcessHeap(), 0, handled_dlls
,
134 new_count
* sizeof(*handled_dlls
) );
135 else new_dlls
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*handled_dlls
) );
136 if (!new_dlls
) return FALSE
;
137 handled_dlls
= new_dlls
;
138 handled_total
= new_count
;
141 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
142 handled_dlls
[i
] = wcsdup( name
);
147 static int is_valid_ptr( const void *data
, SIZE_T size
, const void *ptr
, SIZE_T ptr_size
)
149 if (ptr
< data
) return 0;
150 if ((char *)ptr
- (char *)data
>= size
) return 0;
151 return (size
- ((char *)ptr
- (char *)data
) >= ptr_size
);
154 /* extract the 16-bit NE dll from a PE builtin */
155 static void extract_16bit_image( IMAGE_NT_HEADERS
*nt
, void **data
, SIZE_T
*size
)
157 DWORD exp_size
, *size_ptr
;
158 IMAGE_DOS_HEADER
*dos
;
159 IMAGE_EXPORT_DIRECTORY
*exports
;
160 IMAGE_SECTION_HEADER
*section
= NULL
;
162 DWORD
*names
, *functions
;
165 exports
= RtlImageDirectoryEntryToData( *data
, FALSE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
166 if (!is_valid_ptr( *data
, *size
, exports
, exp_size
)) return;
167 ordinals
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNameOrdinals
, §ion
);
168 names
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfNames
, §ion
);
169 functions
= RtlImageRvaToVa( nt
, *data
, exports
->AddressOfFunctions
, §ion
);
170 if (!is_valid_ptr( *data
, *size
, ordinals
, exports
->NumberOfNames
* sizeof(*ordinals
) )) return;
171 if (!is_valid_ptr( *data
, *size
, names
, exports
->NumberOfNames
* sizeof(*names
) )) return;
173 for (i
= 0; i
< exports
->NumberOfNames
; i
++)
175 char *ename
= RtlImageRvaToVa( nt
, *data
, names
[i
], §ion
);
176 if (strcmp( ename
, "__wine_spec_dos_header" )) continue;
177 if (ordinals
[i
] >= exports
->NumberOfFunctions
) return;
178 if (!is_valid_ptr( *data
, *size
, functions
, sizeof(*functions
) )) return;
179 if (!functions
[ordinals
[i
]]) return;
180 dos
= RtlImageRvaToVa( nt
, *data
, functions
[ordinals
[i
]], NULL
);
181 if (!is_valid_ptr( *data
, *size
, dos
, sizeof(*dos
) )) return;
182 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return;
183 size_ptr
= (DWORD
*)dos
->e_res2
;
184 *size
= min( *size_ptr
, *size
- ((const char *)dos
- (const char *)*data
) );
191 /* read in the contents of a file into the global file buffer */
192 /* return 1 on success, 0 on nonexistent file, -1 on other error */
193 static int read_file( const WCHAR
*name
, void **data
, SIZE_T
*size
, BOOL expect_builtin
)
198 IMAGE_DOS_HEADER
*dos
;
199 IMAGE_NT_HEADERS
*nt
;
200 const char *signature
= expect_builtin
? builtin_signature
: fakedll_signature
;
201 const size_t min_size
= sizeof(*dos
) + 32 +
202 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
204 if ((fd
= _wopen( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
205 if (fstat( fd
, &st
) == -1) goto done
;
207 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
209 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
211 file_buffer_size
= st
.st_size
;
212 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
213 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
216 /* check for valid fake dll file */
218 if (st
.st_size
< min_size
) goto done
;
219 header_size
= min( st
.st_size
, 4096 );
220 if (read( fd
, file_buffer
, header_size
) != header_size
) goto done
;
222 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
223 if (dos
->e_lfanew
< strlen(signature
) + 1) goto done
;
224 if (memcmp( dos
+ 1, signature
, strlen(signature
) + 1 )) goto done
;
225 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
227 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
228 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
230 /* wrong 32/64 type, pretend it doesn't exist */
234 if (st
.st_size
== header_size
||
235 read( fd
, (char *)file_buffer
+ header_size
,
236 st
.st_size
- header_size
) == st
.st_size
- header_size
)
239 if (lstrlenW(name
) > 2 && !wcscmp( name
+ lstrlenW(name
) - 2, L
"16" ))
240 extract_16bit_image( nt
, data
, size
);
248 /* build a complete fake dll from scratch */
249 static BOOL
build_fake_dll( HANDLE file
, const WCHAR
*name
)
251 IMAGE_DOS_HEADER
*dos
;
252 IMAGE_NT_HEADERS
*nt
;
253 struct dll_info info
;
257 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
258 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
261 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
263 dos
= (IMAGE_DOS_HEADER
*)buffer
;
264 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
265 dos
->e_cblp
= sizeof(*dos
);
267 dos
->e_cparhdr
= lfanew
/ 16;
269 dos
->e_maxalloc
= 0xffff;
272 dos
->e_lfarlc
= lfanew
;
273 dos
->e_lfanew
= lfanew
;
274 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
276 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
277 /* some fields are copied from the source dll */
278 #if defined __x86_64__
279 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
280 #elif defined __aarch64__
281 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARM64
;
282 #elif defined __arm__
283 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_ARMNT
;
285 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
287 nt
->FileHeader
.TimeDateStamp
= 0;
288 nt
->FileHeader
.Characteristics
= 0;
289 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
290 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
291 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
292 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
293 nt
->OptionalHeader
.MajorImageVersion
= 1;
294 nt
->OptionalHeader
.MinorImageVersion
= 0;
295 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
296 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
297 nt
->OptionalHeader
.Win32VersionValue
= 0;
298 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
299 nt
->OptionalHeader
.DllCharacteristics
= 0;
300 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
301 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
302 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
303 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
304 /* other fields have fixed values */
305 nt
->Signature
= IMAGE_NT_SIGNATURE
;
306 nt
->FileHeader
.NumberOfSections
= 0;
307 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
308 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
309 nt
->OptionalHeader
.ImageBase
= 0x10000000;
310 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
311 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
312 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
314 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
315 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
316 info
.file_pos
= ALIGN( header_size
, file_alignment
);
318 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
319 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
321 ext
= wcsrchr( name
, '.' );
322 if (!ext
|| wcsicmp( ext
, L
".exe" )) nt
->FileHeader
.Characteristics
|= IMAGE_FILE_DLL
;
324 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
326 size
= sizeof(dll_code_section
);
327 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
331 size
= sizeof(exe_code_section
);
332 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
334 nt
->OptionalHeader
.SizeOfCode
= size
;
335 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
337 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
338 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
339 add_section( &info
, ".reloc", sizeof(reloc_section
),
340 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
342 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
343 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
344 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
345 ret
= xwrite( &info
, buffer
, header_size
, 0 );
347 HeapFree( GetProcessHeap(), 0, buffer
);
351 /* check if an existing file is a fake dll so that we can overwrite it */
352 static BOOL
is_fake_dll( HANDLE h
)
354 IMAGE_DOS_HEADER
*dos
;
356 BYTE buffer
[sizeof(*dos
) + 32];
358 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
360 dos
= (IMAGE_DOS_HEADER
*)buffer
;
361 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
362 if (dos
->e_lfanew
< size
) return FALSE
;
363 return (!memcmp( dos
+ 1, builtin_signature
, sizeof(builtin_signature
) ) ||
364 !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) ));
367 /* create directories leading to a given file */
368 static void create_directories( const WCHAR
*name
)
372 /* create the directory/directories */
373 path
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name
) + 1)*sizeof(WCHAR
));
374 lstrcpyW(path
, name
);
376 p
= wcschr(path
, '\\');
380 if (!CreateDirectoryW(path
, NULL
))
381 TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path
), GetLastError());
383 p
= wcschr(p
+1, '\\');
385 HeapFree(GetProcessHeap(), 0, path
);
388 static inline WCHAR
*prepend( WCHAR
*buffer
, const WCHAR
*str
, size_t len
)
390 return memcpy( buffer
- len
, str
, len
* sizeof(WCHAR
) );
393 static const WCHAR
*enum_load_path( unsigned int idx
)
396 swprintf( buffer
, ARRAY_SIZE(buffer
), L
"WINEDLLDIR%u", idx
);
397 return _wgetenv( buffer
);
400 /* try to load a pre-compiled fake dll */
401 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
403 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
407 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
411 if ((p
= wcsrchr( name
, '\\' ))) name
= p
+ 1;
414 len
= lstrlenW( name
);
415 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + len
+ 1;
416 while ((path
= enum_load_path( i
++ ))) maxlen
= max( maxlen
, lstrlenW(path
) );
417 maxlen
+= ARRAY_SIZE(L
"\\fakedlls") + len
+ ARRAY_SIZE(L
".fake");
419 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return NULL
;
421 pos
= maxlen
- len
- ARRAY_SIZE(L
".fake");
422 lstrcpyW( file
+ pos
, name
);
430 file
[pos
+ len
+ 1] = 0;
431 if (namelen
> 4 && !wcsncmp( ptr
+ namelen
- 4, L
".dll", 4 )) namelen
-= 4;
432 ptr
= prepend( ptr
, ptr
, namelen
);
433 ptr
= prepend( ptr
, L
"\\dlls", 5 );
434 ptr
= prepend( ptr
, build_dir
, lstrlenW(build_dir
) );
435 if ((res
= read_file( ptr
, &data
, size
, TRUE
))) goto done
;
436 lstrcpyW( file
+ pos
+ len
+ 1, L
".fake" );
437 if ((res
= read_file( ptr
, &data
, size
, FALSE
))) goto done
;
439 /* now as a program */
442 file
[pos
+ len
+ 1] = 0;
443 if (namelen
> 4 && !wcsncmp( ptr
+ namelen
- 4, L
".exe", 4 )) namelen
-= 4;
444 ptr
= prepend( ptr
, ptr
, namelen
);
445 ptr
= prepend( ptr
, L
"\\programs", 9 );
446 ptr
= prepend( ptr
, build_dir
, lstrlenW(build_dir
) );
447 if ((res
= read_file( ptr
, &data
, size
, TRUE
))) goto done
;
448 lstrcpyW( file
+ pos
+ len
+ 1, L
".fake" );
449 if ((res
= read_file( ptr
, &data
, size
, FALSE
))) goto done
;
452 file
[pos
+ len
+ 1] = 0;
453 for (i
= 0; (path
= enum_load_path( i
)); i
++)
455 ptr
= prepend( file
+ pos
, path
, lstrlenW(path
) );
456 if ((res
= read_file( ptr
, &data
, size
, TRUE
))) break;
457 ptr
= prepend( file
+ pos
, L
"\\fakedlls", 9 );
458 ptr
= prepend( ptr
, path
, lstrlenW(path
) );
459 if ((res
= read_file( ptr
, &data
, size
, FALSE
))) break;
463 HeapFree( GetProcessHeap(), 0, file
);
464 if (res
== 1) return data
;
468 /* create the fake dll destination file */
469 static HANDLE
create_dest_file( const WCHAR
*name
)
471 /* first check for an existing file */
472 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
473 if (h
!= INVALID_HANDLE_VALUE
)
475 if (!is_fake_dll( h
))
477 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
481 /* truncate the file */
482 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
487 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
489 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
490 if (h
== INVALID_HANDLE_VALUE
)
491 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
496 /* XML parsing code copied from ntdll */
510 static inline BOOL
xmlstr_cmp(const xmlstr_t
* xmlstr
, const char *str
)
512 return !strncmp(xmlstr
->ptr
, str
, xmlstr
->len
) && !str
[xmlstr
->len
];
515 static inline BOOL
isxmlspace( char ch
)
517 return (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== '\t');
520 static BOOL
next_xml_elem( xmlbuf_t
*xmlbuf
, xmlstr_t
*elem
)
526 ptr
= memchr(xmlbuf
->ptr
, '<', xmlbuf
->end
- xmlbuf
->ptr
);
529 xmlbuf
->ptr
= xmlbuf
->end
;
533 if (ptr
+ 3 < xmlbuf
->end
&& ptr
[0] == '!' && ptr
[1] == '-' && ptr
[2] == '-') /* skip comment */
535 for (ptr
+= 3; ptr
+ 3 <= xmlbuf
->end
; ptr
++)
536 if (ptr
[0] == '-' && ptr
[1] == '-' && ptr
[2] == '>') break;
538 if (ptr
+ 3 > xmlbuf
->end
)
540 xmlbuf
->ptr
= xmlbuf
->end
;
543 xmlbuf
->ptr
= ptr
+ 3;
549 while (ptr
< xmlbuf
->end
&& !isxmlspace(*ptr
) && *ptr
!= '>' && (*ptr
!= '/' || ptr
== xmlbuf
->ptr
))
552 elem
->ptr
= xmlbuf
->ptr
;
553 elem
->len
= ptr
- xmlbuf
->ptr
;
555 return xmlbuf
->ptr
!= xmlbuf
->end
;
558 static BOOL
next_xml_attr(xmlbuf_t
* xmlbuf
, xmlstr_t
* name
, xmlstr_t
* value
, BOOL
* error
)
564 while (xmlbuf
->ptr
< xmlbuf
->end
&& isxmlspace(*xmlbuf
->ptr
))
567 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
569 if (*xmlbuf
->ptr
== '/')
572 if (xmlbuf
->ptr
== xmlbuf
->end
|| *xmlbuf
->ptr
!= '>')
580 if (*xmlbuf
->ptr
== '>')
588 while (ptr
< xmlbuf
->end
&& *ptr
!= '=' && *ptr
!= '>' && !isxmlspace(*ptr
)) ptr
++;
590 if (ptr
== xmlbuf
->end
|| *ptr
!= '=') return FALSE
;
592 name
->ptr
= xmlbuf
->ptr
;
593 name
->len
= ptr
-xmlbuf
->ptr
;
597 if (ptr
== xmlbuf
->end
|| (*ptr
!= '"' && *ptr
!= '\'')) return FALSE
;
600 if (ptr
== xmlbuf
->end
) return FALSE
;
602 ptr
= memchr(ptr
, ptr
[-1], xmlbuf
->end
- ptr
);
605 xmlbuf
->ptr
= xmlbuf
->end
;
609 value
->len
= ptr
- value
->ptr
;
610 xmlbuf
->ptr
= ptr
+ 1;
612 if (xmlbuf
->ptr
== xmlbuf
->end
) return FALSE
;
618 static void append_manifest_filename( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
619 const xmlstr_t
*version
, const xmlstr_t
*lang
, WCHAR
*buffer
, DWORD size
)
621 DWORD pos
= lstrlenW( buffer
);
623 pos
+= MultiByteToWideChar( CP_UTF8
, 0, arch
->ptr
, arch
->len
, buffer
+ pos
, size
- pos
);
625 pos
+= MultiByteToWideChar( CP_UTF8
, 0, name
->ptr
, name
->len
, buffer
+ pos
, size
- pos
);
627 pos
+= MultiByteToWideChar( CP_UTF8
, 0, key
->ptr
, key
->len
, buffer
+ pos
, size
- pos
);
629 pos
+= MultiByteToWideChar( CP_UTF8
, 0, version
->ptr
, version
->len
, buffer
+ pos
, size
- pos
);
631 pos
+= MultiByteToWideChar( CP_UTF8
, 0, lang
->ptr
, lang
->len
, buffer
+ pos
, size
- pos
);
632 lstrcpyW( buffer
+ pos
, L
"_deadbeef" );
636 static WCHAR
* create_winsxs_dll_path( const xmlstr_t
*arch
, const xmlstr_t
*name
,
637 const xmlstr_t
*key
, const xmlstr_t
*version
,
638 const xmlstr_t
*lang
)
643 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\" )
644 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 19;
646 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
647 GetWindowsDirectoryW( path
, path_len
);
648 lstrcatW( path
, L
"\\winsxs\\" );
649 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
650 lstrcatW( path
, L
"\\" );
654 static BOOL
create_manifest( const xmlstr_t
*arch
, const xmlstr_t
*name
, const xmlstr_t
*key
,
655 const xmlstr_t
*version
, const xmlstr_t
*lang
, const void *data
, DWORD len
)
658 DWORD written
, path_len
;
662 path_len
= GetWindowsDirectoryW( NULL
, 0 ) + ARRAY_SIZE( L
"\\winsxs\\manifests\\" )
663 + arch
->len
+ name
->len
+ key
->len
+ version
->len
+ 18 + ARRAY_SIZE( L
".manifest" );
665 path
= HeapAlloc( GetProcessHeap(), 0, path_len
* sizeof(WCHAR
) );
666 GetWindowsDirectoryW( path
, path_len
);
667 lstrcatW( path
, L
"\\winsxs\\manifests\\" );
668 append_manifest_filename( arch
, name
, key
, version
, lang
, path
, path_len
);
669 lstrcatW( path
, L
".manifest" );
670 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
671 if (handle
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_PATH_NOT_FOUND
)
673 create_directories( path
);
674 handle
= CreateFileW( path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
677 if (handle
!= INVALID_HANDLE_VALUE
)
679 TRACE( "creating %s\n", debugstr_w(path
) );
680 ret
= (WriteFile( handle
, data
, len
, &written
, NULL
) && written
== len
);
681 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(path
), GetLastError() );
682 CloseHandle( handle
);
683 if (!ret
) DeleteFileW( path
);
685 HeapFree( GetProcessHeap(), 0, path
);
699 struct list
*delay_copy
;
700 const WCHAR
*src_dir
;
704 static BOOL CALLBACK
register_manifest( HMODULE module
, const WCHAR
*type
, WCHAR
*res_name
, LONG_PTR arg
)
707 static const char current_arch
[] = "x86";
708 #elif defined __x86_64__
709 static const char current_arch
[] = "amd64";
710 #elif defined __arm__
711 static const char current_arch
[] = "arm";
712 #elif defined __aarch64__
713 static const char current_arch
[] = "arm64";
715 static const char current_arch
[] = "none";
717 const struct dll_data
*dll_data
= (const struct dll_data
*)arg
;
721 xmlstr_t elem
, attr_name
, attr_value
;
722 xmlstr_t name
, version
, arch
, key
, lang
;
724 const char *manifest
;
728 if (IS_INTRESOURCE( res_name
) || wcsncmp( res_name
, L
"WINE_MANIFEST", 13 )) return TRUE
;
730 rsrc
= FindResourceW( module
, res_name
, type
);
731 manifest
= LoadResource( module
, rsrc
);
732 len
= SizeofResource( module
, rsrc
);
734 buffer
.ptr
= manifest
;
735 buffer
.end
= manifest
+ len
;
736 name
.ptr
= version
.ptr
= arch
.ptr
= key
.ptr
= lang
.ptr
= NULL
;
737 name
.len
= version
.len
= arch
.len
= key
.len
= lang
.len
= 0;
739 while (next_xml_elem( &buffer
, &elem
))
741 if (xmlstr_cmp( &elem
, "file" ))
743 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
745 if (xmlstr_cmp(&attr_name
, "name"))
752 if (!error
&& dest
&& name
.ptr
)
754 struct delay_copy
*add
= HeapAlloc( GetProcessHeap(), 0,
755 sizeof(*add
) + (dll_data
->src_len
+ name
.len
+
756 dest_len
+ name
.len
+ 1) * sizeof(WCHAR
) );
757 add
->src
= add
->data
;
758 memcpy( add
->src
, dll_data
->src_dir
, dll_data
->src_len
* sizeof(WCHAR
) );
759 MultiByteToWideChar( CP_UTF8
, 0, name
.ptr
, name
.len
,
760 add
->src
+ dll_data
->src_len
, name
.len
);
761 add
->src
[dll_data
->src_len
+ name
.len
] = 0;
762 add
->dest
= add
->data
+ dll_data
->src_len
+ name
.len
+ 1;
763 memcpy( add
->dest
, dest
, dest_len
* sizeof(WCHAR
) );
764 memcpy( add
->dest
+ dest_len
, add
->src
+ dll_data
->src_len
,
765 (name
.len
+ 1) * sizeof(WCHAR
) );
766 TRACE("schedule copy %s -> %s\n", wine_dbgstr_w(add
->src
), wine_dbgstr_w(add
->dest
));
767 list_add_tail( dll_data
->delay_copy
, &add
->entry
);
772 if (!xmlstr_cmp( &elem
, "assemblyIdentity" )) continue;
773 HeapFree( GetProcessHeap(), 0, dest
);
775 while (next_xml_attr( &buffer
, &attr_name
, &attr_value
, &error
))
777 if (xmlstr_cmp(&attr_name
, "name")) name
= attr_value
;
778 else if (xmlstr_cmp(&attr_name
, "version")) version
= attr_value
;
779 else if (xmlstr_cmp(&attr_name
, "processorArchitecture")) arch
= attr_value
;
780 else if (xmlstr_cmp(&attr_name
, "publicKeyToken")) key
= attr_value
;
781 else if (xmlstr_cmp(&attr_name
, "language")) lang
= attr_value
;
783 if (!error
&& name
.ptr
&& version
.ptr
&& arch
.ptr
&& key
.ptr
)
788 lang
.len
= strlen( lang
.ptr
);
790 if (!arch
.len
) /* fixup the architecture */
792 char *new_buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ sizeof(current_arch
) );
793 memcpy( new_buffer
, manifest
, arch
.ptr
- manifest
);
794 strcpy( new_buffer
+ (arch
.ptr
- manifest
), current_arch
);
795 memcpy( new_buffer
+ strlen(new_buffer
), arch
.ptr
, len
- (arch
.ptr
- manifest
) );
796 arch
.ptr
= current_arch
;
797 arch
.len
= strlen( current_arch
);
798 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
799 create_manifest( &arch
, &name
, &key
, &version
, &lang
, new_buffer
, len
+ arch
.len
);
800 HeapFree( GetProcessHeap(), 0, new_buffer
);
804 dest
= create_winsxs_dll_path( &arch
, &name
, &key
, &version
, &lang
);
805 create_manifest( &arch
, &name
, &key
, &version
, &lang
, manifest
, len
);
807 dest_len
= wcslen( dest
);
810 HeapFree( GetProcessHeap(), 0, dest
);
815 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
817 HRESULT
*hr
= (HRESULT
*)arg
;
819 HRSRC rsrc
= FindResourceW( module
, name
, type
);
820 char *str
= LoadResource( module
, rsrc
);
821 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
823 if (!str
) return FALSE
;
824 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
825 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
826 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
827 buffer
[lenW
- 1] = 0;
828 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
829 HeapFree( GetProcessHeap(), 0, buffer
);
833 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
, struct list
*delay_copy
)
835 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
836 LDR_RESOURCE_INFO info
;
838 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
839 struct dll_data dll_data
= { delay_copy
, name
, 0 };
842 if (!(p
= wcsrchr( name
, '\\' ))) p
= name
;
844 dll_data
.src_len
= p
- name
;
845 EnumResourceNamesW( module
, (WCHAR
*)RT_MANIFEST
, register_manifest
, (LONG_PTR
)&dll_data
);
847 info
.Type
= (ULONG_PTR
)L
"WINE_REGISTRY";
848 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
852 HRESULT (WINAPI
*pAtlCreateRegistrar
)(IRegistrar
**);
853 HMODULE atl
= LoadLibraryW( L
"atl100.dll" );
855 if ((pAtlCreateRegistrar
= (void *)GetProcAddress( atl
, "AtlCreateRegistrar" )))
856 hr
= pAtlCreateRegistrar( ®istrar
);
862 ERR( "failed to create IRegistrar: %x\n", hr
);
867 TRACE( "registering %s\n", debugstr_w(name
) );
868 IRegistrar_ClearReplacements( registrar
);
869 IRegistrar_AddReplacement( registrar
, L
"MODULE", name
);
870 EnumResourceNamesW( module
, L
"WINE_REGISTRY", register_resource
, (LONG_PTR
)&hr
);
871 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
874 /* copy a fake dll file to the dest directory */
875 static int install_fake_dll( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*ext
, BOOL expect_builtin
, struct list
*delay_copy
)
881 WCHAR
*destname
= dest
+ lstrlenW(dest
);
882 WCHAR
*name
= wcsrchr( file
, '\\' ) + 1;
883 WCHAR
*end
= name
+ lstrlenW(name
);
884 SIZE_T len
= end
- name
;
886 if (ext
) lstrcpyW( end
, ext
);
887 if (!(ret
= read_file( file
, &data
, &size
, expect_builtin
)))
893 if (end
> name
+ 2 && !wcsncmp( end
- 2, L
"16", 2 )) len
-= 2; /* remove "16" suffix */
894 memcpy( destname
, name
, len
* sizeof(WCHAR
) );
896 if (!add_handled_dll( destname
)) ret
= -1;
900 HANDLE h
= create_dest_file( dest
);
902 if (h
&& h
!= INVALID_HANDLE_VALUE
)
904 TRACE( "%s -> %s\n", debugstr_w(file
), debugstr_w(dest
) );
906 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
907 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
909 if (ret
) register_fake_dll( dest
, data
, size
, delay_copy
);
910 else DeleteFileW( dest
);
913 *destname
= 0; /* restore it for next file */
918 static void delay_copy_files( struct list
*delay_copy
)
920 struct delay_copy
*copy
, *next
;
927 LIST_FOR_EACH_ENTRY_SAFE( copy
, next
, delay_copy
, struct delay_copy
, entry
)
929 list_remove( ©
->entry
);
930 ret
= read_file( copy
->src
, &data
, &size
, TRUE
);
931 if (ret
== -1) ret
= read_file( copy
->src
, &data
, &size
, FALSE
);
934 HeapFree( GetProcessHeap(), 0, copy
);
938 h
= create_dest_file( copy
->dest
);
939 if (h
&& h
!= INVALID_HANDLE_VALUE
)
941 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
942 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(copy
->dest
), GetLastError() );
944 if (!ret
) DeleteFileW( copy
->dest
);
946 HeapFree( GetProcessHeap(), 0, copy
);
950 /* find and install all fake dlls in a given lib directory */
951 static void install_lib_dir( WCHAR
*dest
, WCHAR
*file
, const WCHAR
*default_ext
, BOOL expect_builtin
)
955 struct _wfinddata_t data
;
956 struct list delay_copy
= LIST_INIT( delay_copy
);
958 file
[1] = '\\'; /* change \??\ to \\?\ */
959 name
= file
+ lstrlenW(file
);
961 lstrcpyW( name
, L
"*" );
963 if ((handle
= _wfindfirst( file
, &data
)) == -1) return;
966 if (lstrlenW( data
.name
) > max_dll_name_len
) continue;
967 if (!wcscmp( data
.name
, L
"." )) continue;
968 if (!wcscmp( data
.name
, L
".." )) continue;
969 lstrcpyW( name
, data
.name
);
970 if (default_ext
) /* inside build dir */
972 lstrcatW( name
, L
"\\" );
973 lstrcatW( name
, data
.name
);
974 if (wcschr( data
.name
, '.' )) /* module possibly already has an extension */
976 if (install_fake_dll( dest
, file
, NULL
, expect_builtin
, &delay_copy
)) continue;
977 if (install_fake_dll( dest
, file
, L
".fake", FALSE
, &delay_copy
)) continue;
979 lstrcatW( name
, default_ext
);
980 if (install_fake_dll( dest
, file
, NULL
, expect_builtin
, &delay_copy
)) continue;
981 if (install_fake_dll( dest
, file
, L
".fake", FALSE
, &delay_copy
)) continue;
983 else install_fake_dll( dest
, file
, NULL
, expect_builtin
, &delay_copy
);
985 while (!_wfindnext( handle
, &data
));
986 _findclose( handle
);
988 delay_copy_files( &delay_copy
);
991 /* create fake dlls in dirname for all the files we can find */
992 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
)
994 const WCHAR
*build_dir
= _wgetenv( L
"WINEBUILDDIR" );
996 unsigned int i
, maxlen
= 0;
999 if (build_dir
) maxlen
= lstrlenW(build_dir
) + ARRAY_SIZE(L
"\\programs") + 1;
1000 for (i
= 0; (path
= enum_load_path(i
)); i
++) maxlen
= max( maxlen
, lstrlenW(path
) );
1001 maxlen
+= 2 * max_dll_name_len
+ 2 + 10; /* ".dll.fake" */
1002 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
* sizeof(WCHAR
) ))) return FALSE
;
1004 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
1006 HeapFree( GetProcessHeap(), 0, file
);
1009 lstrcpyW( dest
, dirname
);
1010 dest
[lstrlenW(dest
) - 1] = 0; /* remove wildcard */
1014 lstrcpyW( file
, build_dir
);
1015 lstrcatW( file
, L
"\\dlls" );
1016 install_lib_dir( dest
, file
, L
".dll", TRUE
);
1017 lstrcpyW( file
, build_dir
);
1018 lstrcatW( file
, L
"\\programs" );
1019 install_lib_dir( dest
, file
, L
".exe", TRUE
);
1021 for (i
= 0; (path
= enum_load_path( i
)); i
++)
1023 lstrcpyW( file
, path
);
1024 install_lib_dir( dest
, file
, NULL
, TRUE
);
1025 lstrcpyW( file
, path
);
1026 lstrcatW( file
, L
"\\fakedlls" );
1027 install_lib_dir( dest
, file
, NULL
, FALSE
);
1029 HeapFree( GetProcessHeap(), 0, file
);
1030 HeapFree( GetProcessHeap(), 0, dest
);
1034 /***********************************************************************
1037 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
1039 struct list delay_copy
= LIST_INIT( delay_copy
);
1043 const WCHAR
*filename
;
1046 if (!(filename
= wcsrchr( name
, '\\' ))) filename
= name
;
1049 /* check for empty name which means to only create the directory */
1052 create_directories( name
);
1055 if (filename
[0] == '*' && !filename
[1]) return create_wildcard_dlls( name
);
1057 add_handled_dll( filename
);
1059 if (!(h
= create_dest_file( name
))) return TRUE
; /* not a fake dll */
1060 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
1062 if (source
[0] == '-' && !source
[1])
1064 /* '-' source means delete the file */
1065 TRACE( "deleting %s\n", debugstr_w(name
) );
1068 else if ((buffer
= load_fake_dll( source
, &size
)))
1072 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
1073 if (ret
) register_fake_dll( name
, buffer
, size
, &delay_copy
);
1074 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
1078 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
1079 ret
= build_fake_dll( h
, name
);
1083 if (!ret
) DeleteFileW( name
);
1085 delay_copy_files( &delay_copy
);
1090 /***********************************************************************
1093 void cleanup_fake_dlls(void)
1095 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
1097 HeapFree( GetProcessHeap(), 0, handled_dlls
);
1098 handled_dlls
= NULL
;
1099 handled_count
= handled_total
= 0;
1100 if (registrar
) IRegistrar_Release( registrar
);