2 * Creation of Wine fake dlls for apps that access the dll file directly.
4 * Copyright 2006 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
38 #define NONAMELESSSTRUCT
39 #define NONAMELESSUNION
41 #define WIN32_NO_STATUS
47 #include "wine/unicode.h"
48 #include "wine/library.h"
49 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
55 static const char fakedll_signature
[] = "Wine placeholder DLL";
57 static const unsigned int file_alignment
= 512;
58 static const unsigned int section_alignment
= 4096;
59 static const unsigned int max_dll_name_len
= 64;
61 static void *file_buffer
;
62 static SIZE_T file_buffer_size
;
63 static unsigned int handled_count
;
64 static unsigned int handled_total
;
65 static char **handled_dlls
;
66 static IRegistrar
*registrar
;
76 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
78 /* contents of the dll sections */
80 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
81 0xc2, 0x0c, 0x00 }; /* ret $12 */
83 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
84 0xc2, 0x04, 0x00 }; /* ret $4 */
86 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
89 /* wrapper for WriteFile */
90 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
94 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
95 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
99 /* add a new section to the dll NT header */
100 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
102 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
104 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
105 memcpy( sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
106 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
107 sec
->VirtualAddress
= info
->mem_pos
;
108 sec
->SizeOfRawData
= size
;
109 sec
->PointerToRawData
= info
->file_pos
;
110 sec
->Characteristics
= flags
;
111 info
->file_pos
+= ALIGN( size
, file_alignment
);
112 info
->mem_pos
+= ALIGN( size
, section_alignment
);
113 info
->nt
->FileHeader
.NumberOfSections
++;
116 /* add a data directory to the dll NT header */
117 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
119 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
120 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
123 /* convert a dll name W->A without depending on the current codepage */
124 static char *dll_name_WtoA( char *nameA
, const WCHAR
*nameW
, unsigned int len
)
128 for (i
= 0; i
< len
; i
++)
131 if (nameW
[i
] > 127) return NULL
;
132 if (c
>= 'A' && c
<= 'Z') c
+= 'a' - 'A';
139 /* convert a dll name A->W without depending on the current codepage */
140 static WCHAR
*dll_name_AtoW( WCHAR
*nameW
, const char *nameA
, unsigned int len
)
144 for (i
= 0; i
< len
; i
++) nameW
[i
] = nameA
[i
];
149 /* add a dll to the list of dll that have been taken care of */
150 static BOOL
add_handled_dll( const WCHAR
*name
)
152 unsigned int len
= strlenW( name
);
153 int i
, min
, max
, pos
, res
;
156 if (!(nameA
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 ))) return FALSE
;
157 if (!dll_name_WtoA( nameA
, name
, len
)) goto failed
;
160 max
= handled_count
- 1;
163 pos
= (min
+ max
) / 2;
164 res
= strcmp( handled_dlls
[pos
], nameA
);
165 if (!res
) goto failed
; /* already in the list */
166 if (res
< 0) min
= pos
+ 1;
170 if (handled_count
>= handled_total
)
173 unsigned int new_count
= max( 64, handled_total
* 2 );
175 if (handled_dlls
) new_dlls
= HeapReAlloc( GetProcessHeap(), 0, handled_dlls
,
176 new_count
* sizeof(*handled_dlls
) );
177 else new_dlls
= HeapAlloc( GetProcessHeap(), 0, new_count
* sizeof(*handled_dlls
) );
178 if (!new_dlls
) goto failed
;
179 handled_dlls
= new_dlls
;
180 handled_total
= new_count
;
183 for (i
= handled_count
; i
> min
; i
--) handled_dlls
[i
] = handled_dlls
[i
- 1];
184 handled_dlls
[i
] = nameA
;
189 HeapFree( GetProcessHeap(), 0, nameA
);
193 /* read in the contents of a file into the global file buffer */
194 /* return 1 on success, 0 on nonexistent file, -1 on other error */
195 static int read_file( const char *name
, void **data
, SIZE_T
*size
)
200 IMAGE_DOS_HEADER
*dos
;
201 IMAGE_NT_HEADERS
*nt
;
202 const size_t min_size
= sizeof(*dos
) + sizeof(fakedll_signature
) +
203 FIELD_OFFSET( IMAGE_NT_HEADERS
, OptionalHeader
.MajorLinkerVersion
);
205 if ((fd
= open( name
, O_RDONLY
| O_BINARY
)) == -1) return 0;
206 if (fstat( fd
, &st
) == -1) goto done
;
208 if (!file_buffer
|| st
.st_size
> file_buffer_size
)
210 VirtualFree( file_buffer
, 0, MEM_RELEASE
);
212 file_buffer_size
= st
.st_size
;
213 if (NtAllocateVirtualMemory( GetCurrentProcess(), &file_buffer
, 0, &file_buffer_size
,
214 MEM_COMMIT
, PAGE_READWRITE
)) goto done
;
217 /* check for valid fake dll file */
219 if (st
.st_size
< min_size
) goto done
;
220 header_size
= min( st
.st_size
, 4096 );
221 if (pread( fd
, file_buffer
, header_size
, 0 ) != header_size
) goto done
;
223 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto done
;
224 if (dos
->e_lfanew
< sizeof(fakedll_signature
)) goto done
;
225 if (memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) )) goto done
;
226 if (dos
->e_lfanew
+ FIELD_OFFSET(IMAGE_NT_HEADERS
,OptionalHeader
.MajorLinkerVersion
) > header_size
)
228 nt
= (IMAGE_NT_HEADERS
*)((char *)file_buffer
+ dos
->e_lfanew
);
229 if (nt
->Signature
== IMAGE_NT_SIGNATURE
&& nt
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
231 /* wrong 32/64 type, pretend it doesn't exist */
235 if (st
.st_size
== header_size
||
236 pread( fd
, (char *)file_buffer
+ header_size
,
237 st
.st_size
- header_size
, header_size
) == st
.st_size
- header_size
)
247 /* build a complete fake dll from scratch */
248 static BOOL
build_fake_dll( HANDLE file
)
250 IMAGE_DOS_HEADER
*dos
;
251 IMAGE_NT_HEADERS
*nt
;
252 struct dll_info info
;
255 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
256 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
259 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
261 dos
= (IMAGE_DOS_HEADER
*)buffer
;
262 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
263 dos
->e_cblp
= sizeof(*dos
);
265 dos
->e_cparhdr
= lfanew
/ 16;
267 dos
->e_maxalloc
= 0xffff;
270 dos
->e_lfarlc
= lfanew
;
271 dos
->e_lfanew
= lfanew
;
272 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
274 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
275 /* some fields are copied from the source dll */
277 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_AMD64
;
279 nt
->FileHeader
.Machine
= IMAGE_FILE_MACHINE_I386
;
281 nt
->FileHeader
.TimeDateStamp
= 0;
282 nt
->FileHeader
.Characteristics
= IMAGE_FILE_DLL
;
283 nt
->OptionalHeader
.MajorLinkerVersion
= 1;
284 nt
->OptionalHeader
.MinorLinkerVersion
= 0;
285 nt
->OptionalHeader
.MajorOperatingSystemVersion
= 1;
286 nt
->OptionalHeader
.MinorOperatingSystemVersion
= 0;
287 nt
->OptionalHeader
.MajorImageVersion
= 1;
288 nt
->OptionalHeader
.MinorImageVersion
= 0;
289 nt
->OptionalHeader
.MajorSubsystemVersion
= 4;
290 nt
->OptionalHeader
.MinorSubsystemVersion
= 0;
291 nt
->OptionalHeader
.Win32VersionValue
= 0;
292 nt
->OptionalHeader
.Subsystem
= IMAGE_SUBSYSTEM_WINDOWS_GUI
;
293 nt
->OptionalHeader
.DllCharacteristics
= 0;
294 nt
->OptionalHeader
.SizeOfStackReserve
= 0;
295 nt
->OptionalHeader
.SizeOfStackCommit
= 0;
296 nt
->OptionalHeader
.SizeOfHeapReserve
= 0;
297 nt
->OptionalHeader
.SizeOfHeapCommit
= 0;
298 /* other fields have fixed values */
299 nt
->Signature
= IMAGE_NT_SIGNATURE
;
300 nt
->FileHeader
.NumberOfSections
= 0;
301 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
302 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
303 nt
->OptionalHeader
.ImageBase
= 0x10000000;
304 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
305 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
306 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
308 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
309 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
310 info
.file_pos
= ALIGN( header_size
, file_alignment
);
312 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
313 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
315 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
317 size
= sizeof(dll_code_section
);
318 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
322 size
= sizeof(exe_code_section
);
323 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
325 nt
->OptionalHeader
.SizeOfCode
= size
;
326 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
328 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
329 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
330 add_section( &info
, ".reloc", sizeof(reloc_section
),
331 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
333 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
334 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
335 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
336 ret
= xwrite( &info
, buffer
, header_size
, 0 );
338 HeapFree( GetProcessHeap(), 0, buffer
);
342 /* check if an existing file is a fake dll so that we can overwrite it */
343 static BOOL
is_fake_dll( HANDLE h
)
345 IMAGE_DOS_HEADER
*dos
;
347 BYTE buffer
[sizeof(*dos
) + sizeof(fakedll_signature
)];
349 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
351 dos
= (IMAGE_DOS_HEADER
*)buffer
;
352 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
353 if (dos
->e_lfanew
< size
) return FALSE
;
354 return !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
357 /* create directories leading to a given file */
358 static void create_directories( const WCHAR
*name
)
362 /* create the directory/directories */
363 path
= HeapAlloc(GetProcessHeap(), 0, (strlenW(name
) + 1)*sizeof(WCHAR
));
366 p
= strchrW(path
, '\\');
370 if (!CreateDirectoryW(path
, NULL
))
371 TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path
), GetLastError());
373 p
= strchrW(p
+1, '\\');
375 HeapFree(GetProcessHeap(), 0, path
);
378 static inline char *prepend( char *buffer
, const char *str
, size_t len
)
380 return memcpy( buffer
- len
, str
, len
);
383 /* try to load a pre-compiled fake dll */
384 static void *load_fake_dll( const WCHAR
*name
, SIZE_T
*size
)
386 const char *build_dir
= wine_get_build_dir();
390 unsigned int i
, pos
, len
, namelen
, maxlen
= 0;
394 if ((p
= strrchrW( name
, '\\' ))) name
= p
+ 1;
397 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/") + strlenW(name
);
398 while ((path
= wine_dll_enum_load_path( i
++ ))) maxlen
= max( maxlen
, strlen(path
) );
399 maxlen
+= sizeof("/fakedlls") + strlenW(name
) + 2;
401 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return NULL
;
403 len
= strlenW( name
);
404 pos
= maxlen
- len
- sizeof(".fake");
405 if (!dll_name_WtoA( file
+ pos
, name
, len
)) goto done
;
410 strcpy( file
+ pos
+ len
+ 1, ".fake" );
415 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".dll", 4 )) namelen
-= 4;
416 ptr
= prepend( ptr
, ptr
, namelen
);
417 ptr
= prepend( ptr
, "/dlls", sizeof("/dlls") - 1 );
418 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
419 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
421 /* now as a program */
424 if (namelen
> 4 && !memcmp( ptr
+ namelen
- 4, ".exe", 4 )) namelen
-= 4;
425 ptr
= prepend( ptr
, ptr
, namelen
);
426 ptr
= prepend( ptr
, "/programs", sizeof("/programs") - 1 );
427 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
428 if ((res
= read_file( ptr
, &data
, size
))) goto done
;
431 file
[pos
+ len
+ 1] = 0;
432 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
434 ptr
= prepend( file
+ pos
, "/fakedlls", sizeof("/fakedlls") - 1 );
435 ptr
= prepend( ptr
, path
, strlen(path
) );
436 if ((res
= read_file( ptr
, &data
, size
))) break;
440 HeapFree( GetProcessHeap(), 0, file
);
441 if (res
== 1) return data
;
445 /* create the fake dll destination file */
446 static HANDLE
create_dest_file( const WCHAR
*name
)
448 /* first check for an existing file */
449 HANDLE h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
450 if (h
!= INVALID_HANDLE_VALUE
)
452 if (!is_fake_dll( h
))
454 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
458 /* truncate the file */
459 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
464 if (GetLastError() == ERROR_PATH_NOT_FOUND
) create_directories( name
);
466 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
467 if (h
== INVALID_HANDLE_VALUE
)
468 ERR( "failed to create %s (error=%u)\n", debugstr_w(name
), GetLastError() );
473 static BOOL CALLBACK
register_resource( HMODULE module
, LPCWSTR type
, LPWSTR name
, LONG_PTR arg
)
475 HRESULT
*hr
= (HRESULT
*)arg
;
477 HRSRC rsrc
= FindResourceW( module
, name
, type
);
478 char *str
= LoadResource( module
, rsrc
);
479 DWORD lenW
, lenA
= SizeofResource( module
, rsrc
);
481 if (!str
) return FALSE
;
482 lenW
= MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, NULL
, 0 ) + 1;
483 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) ))) return FALSE
;
484 MultiByteToWideChar( CP_UTF8
, 0, str
, lenA
, buffer
, lenW
);
485 buffer
[lenW
- 1] = 0;
486 *hr
= IRegistrar_StringRegister( registrar
, buffer
);
487 HeapFree( GetProcessHeap(), 0, buffer
);
491 static void register_fake_dll( const WCHAR
*name
, const void *data
, size_t size
)
493 static const WCHAR atlW
[] = {'a','t','l','.','d','l','l',0};
494 static const WCHAR moduleW
[] = {'M','O','D','U','L','E',0};
495 static const WCHAR regtypeW
[] = {'W','I','N','E','_','R','E','G','I','S','T','R','Y',0};
496 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
497 LDR_RESOURCE_INFO info
;
499 HMODULE module
= (HMODULE
)((ULONG_PTR
)data
| 1);
501 info
.Type
= (ULONG_PTR
)regtypeW
;
502 if (LdrFindResourceDirectory_U( module
, &info
, 1, &resdir
)) return;
506 /* create the object by hand since we can't guarantee that atl and ole32 are registered */
508 HRESULT (WINAPI
*pDllGetClassObject
)( REFCLSID clsid
, REFIID iid
, LPVOID
*ppv
);
509 HMODULE atl
= LoadLibraryW( atlW
);
511 if ((pDllGetClassObject
= (void *)GetProcAddress( atl
, "DllGetClassObject" )))
513 hr
= pDllGetClassObject( &CLSID_Registrar
, &IID_IClassFactory
, (void **)&cf
);
516 hr
= IClassFactory_CreateInstance( cf
, NULL
, &IID_IRegistrar
, (void **)®istrar
);
517 IClassFactory_Release( cf
);
522 ERR( "failed to create IRegistrar: %x\n", hr
);
527 TRACE( "registering %s\n", debugstr_w(name
) );
528 IRegistrar_ClearReplacements( registrar
);
529 IRegistrar_AddReplacement( registrar
, moduleW
, name
);
530 EnumResourceNamesW( module
, regtypeW
, register_resource
, (LONG_PTR
)&hr
);
531 if (FAILED(hr
)) ERR( "failed to register %s: %x\n", debugstr_w(name
), hr
);
534 /* copy a fake dll file to the dest directory */
535 static void install_fake_dll( WCHAR
*dest
, char *file
, const char *ext
)
541 WCHAR
*destname
= dest
+ strlenW(dest
);
542 char *name
= strrchr( file
, '/' ) + 1;
543 char *end
= name
+ strlen(name
);
545 if (ext
) strcpy( end
, ext
);
546 if (!(ret
= read_file( file
, &data
, &size
))) return;
548 if (end
> name
+ 2 && !strncmp( end
- 2, "16", 2 )) end
-= 2; /* remove "16" suffix */
549 dll_name_AtoW( destname
, name
, end
- name
);
550 if (!add_handled_dll( destname
)) ret
= -1;
554 HANDLE h
= create_dest_file( dest
);
556 if (h
&& h
!= INVALID_HANDLE_VALUE
)
558 TRACE( "%s -> %s\n", debugstr_a(file
), debugstr_w(dest
) );
560 ret
= (WriteFile( h
, data
, size
, &written
, NULL
) && written
== size
);
561 if (!ret
) ERR( "failed to write to %s (error=%u)\n", debugstr_w(dest
), GetLastError() );
563 if (ret
) register_fake_dll( dest
, data
, size
);
564 else DeleteFileW( dest
);
567 *destname
= 0; /* restore it for next file */
570 /* find and install all fake dlls in a given lib directory */
571 static void install_lib_dir( WCHAR
*dest
, char *file
, const char *default_ext
)
577 if (!(dir
= opendir( file
))) return;
578 name
= file
+ strlen(file
);
580 while ((de
= readdir( dir
)))
582 if (strlen( de
->d_name
) > max_dll_name_len
) continue;
583 if (!strcmp( de
->d_name
, "." )) continue;
584 if (!strcmp( de
->d_name
, ".." )) continue;
585 strcpy( name
, de
->d_name
);
586 if (default_ext
) /* inside build dir */
589 strcat( name
, de
->d_name
);
590 if (!strchr( de
->d_name
, '.' )) strcat( name
, default_ext
);
591 install_fake_dll( dest
, file
, ".fake" );
593 else install_fake_dll( dest
, file
, NULL
);
598 /* create fake dlls in dirname for all the files we can find */
599 static BOOL
create_wildcard_dlls( const WCHAR
*dirname
)
601 const char *build_dir
= wine_get_build_dir();
603 unsigned int i
, maxlen
= 0;
607 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/");
608 for (i
= 0; (path
= wine_dll_enum_load_path(i
)); i
++) maxlen
= max( maxlen
, strlen(path
) );
609 maxlen
+= 2 * max_dll_name_len
+ 2 + sizeof(".dll.fake");
610 if (!(file
= HeapAlloc( GetProcessHeap(), 0, maxlen
))) return FALSE
;
612 if (!(dest
= HeapAlloc( GetProcessHeap(), 0, (strlenW(dirname
) + max_dll_name_len
) * sizeof(WCHAR
) )))
614 HeapFree( GetProcessHeap(), 0, file
);
617 strcpyW( dest
, dirname
);
618 dest
[strlenW(dest
) - 1] = 0; /* remove wildcard */
622 strcpy( file
, build_dir
);
623 strcat( file
, "/dlls" );
624 install_lib_dir( dest
, file
, ".dll" );
625 strcpy( file
, build_dir
);
626 strcat( file
, "/programs" );
627 install_lib_dir( dest
, file
, ".exe" );
629 for (i
= 0; (path
= wine_dll_enum_load_path( i
)); i
++)
631 strcpy( file
, path
);
632 strcat( file
, "/fakedlls" );
633 install_lib_dir( dest
, file
, NULL
);
635 HeapFree( GetProcessHeap(), 0, file
);
636 HeapFree( GetProcessHeap(), 0, dest
);
640 /***********************************************************************
643 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
648 const WCHAR
*filename
;
651 if (!(filename
= strrchrW( name
, '\\' ))) filename
= name
;
654 /* check for empty name which means to only create the directory */
657 create_directories( name
);
660 if (filename
[0] == '*' && !filename
[1]) return create_wildcard_dlls( name
);
662 add_handled_dll( filename
);
664 if (!(h
= create_dest_file( name
))) return TRUE
; /* not a fake dll */
665 if (h
== INVALID_HANDLE_VALUE
) return FALSE
;
667 if (source
[0] == '-' && !source
[1])
669 /* '-' source means delete the file */
670 TRACE( "deleting %s\n", debugstr_w(name
) );
673 else if ((buffer
= load_fake_dll( source
, &size
)))
677 ret
= (WriteFile( h
, buffer
, size
, &written
, NULL
) && written
== size
);
678 if (ret
) register_fake_dll( name
, buffer
, size
);
679 else ERR( "failed to write to %s (error=%u)\n", debugstr_w(name
), GetLastError() );
683 WARN( "fake dll %s not found for %s\n", debugstr_w(source
), debugstr_w(name
) );
684 ret
= build_fake_dll( h
);
688 if (!ret
) DeleteFileW( name
);
693 /***********************************************************************
696 void cleanup_fake_dlls(void)
698 if (file_buffer
) VirtualFree( file_buffer
, 0, MEM_RELEASE
);
700 HeapFree( GetProcessHeap(), 0, handled_dlls
);
702 handled_count
= handled_total
= 0;
703 if (registrar
) IRegistrar_Release( registrar
);