ntdll: Use INT_MAX for the semaphore count since LONG_MAX won't work on 64-bit.
[wine] / dlls / ntdll / loader.c
1 /*
2  * Loader functions
3  *
4  * Copyright 1995, 2003 Alexandre Julliard
5  * Copyright 2002 Dmitry Timoshkov for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
29 #endif
30
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "windef.h"
37 #include "winnt.h"
38 #include "winternl.h"
39
40 #include "wine/exception.h"
41 #include "wine/library.h"
42 #include "wine/pthread.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45 #include "wine/server.h"
46 #include "ntdll_misc.h"
47 #include "ddk/wdm.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(module);
50 WINE_DECLARE_DEBUG_CHANNEL(relay);
51 WINE_DECLARE_DEBUG_CHANNEL(snoop);
52 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
53 WINE_DECLARE_DEBUG_CHANNEL(imports);
54
55 /* we don't want to include winuser.h */
56 #define RT_MANIFEST                         ((ULONG_PTR)24)
57 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
58
59 extern struct wine_pthread_functions pthread_functions;
60
61 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
62
63 static int process_detaching = 0;  /* set on process detach to avoid deadlocks with thread detach */
64 static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
65
66 static const char * const reason_names[] =
67 {
68     "PROCESS_DETACH",
69     "PROCESS_ATTACH",
70     "THREAD_ATTACH",
71     "THREAD_DETACH",
72     NULL, NULL, NULL, NULL,
73     "WINE_PREATTACH"
74 };
75
76 static const WCHAR dllW[] = {'.','d','l','l',0};
77
78 /* internal representation of 32bit modules. per process. */
79 typedef struct _wine_modref
80 {
81     LDR_MODULE            ldr;
82     int                   nDeps;
83     struct _wine_modref **deps;
84 } WINE_MODREF;
85
86 /* info about the current builtin dll load */
87 /* used to keep track of things across the register_dll constructor call */
88 struct builtin_load_info
89 {
90     const WCHAR *load_path;
91     const WCHAR *filename;
92     NTSTATUS     status;
93     WINE_MODREF *wm;
94 };
95
96 static struct builtin_load_info default_load_info;
97 static struct builtin_load_info *builtin_load_info = &default_load_info;
98
99 static HANDLE main_exe_file;
100 static UINT tls_module_count;      /* number of modules with TLS directory */
101 static UINT tls_total_size;        /* total size of TLS storage */
102 static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */
103
104 UNICODE_STRING windows_dir = { 0, 0, NULL };  /* windows directory */
105 UNICODE_STRING system_dir = { 0, 0, NULL };  /* system directory */
106
107 static RTL_CRITICAL_SECTION loader_section;
108 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
109 {
110     0, 0, &loader_section,
111     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
112       0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
113 };
114 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
115
116 static WINE_MODREF *cached_modref;
117 static WINE_MODREF *current_modref;
118 static WINE_MODREF *last_failed_modref;
119
120 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm );
121 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved );
122 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
123                                   DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
124
125 /* convert PE image VirtualAddress to Real Address */
126 static inline void *get_rva( HMODULE module, DWORD va )
127 {
128     return (void *)((char *)module + va);
129 }
130
131 /* check whether the file name contains a path */
132 static inline int contains_path( LPCWSTR name )
133 {
134     return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
135 }
136
137 /* convert from straight ASCII to Unicode without depending on the current codepage */
138 static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
139 {
140     while (len--) *dst++ = (unsigned char)*src++;
141 }
142
143
144 /*************************************************************************
145  *              call_dll_entry_point
146  *
147  * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
148  * their entry point, so we need a small asm wrapper.
149  */
150 #ifdef __i386__
151 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
152 __ASM_GLOBAL_FUNC(call_dll_entry_point,
153                   "pushl %ebp\n\t"
154                   "movl %esp,%ebp\n\t"
155                   "pushl %ebx\n\t"
156                   "subl $8,%esp\n\t"
157                   "pushl 20(%ebp)\n\t"
158                   "pushl 16(%ebp)\n\t"
159                   "pushl 12(%ebp)\n\t"
160                   "movl 8(%ebp),%eax\n\t"
161                   "call *%eax\n\t"
162                   "leal -4(%ebp),%esp\n\t"
163                   "popl %ebx\n\t"
164                   "popl %ebp\n\t"
165                   "ret" )
166 #else /* __i386__ */
167 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
168                                          UINT reason, void *reserved )
169 {
170     return proc( module, reason, reserved );
171 }
172 #endif /* __i386__ */
173
174
175 #if defined(__i386__) || defined(__x86_64__)
176 /*************************************************************************
177  *              stub_entry_point
178  *
179  * Entry point for stub functions.
180  */
181 static void stub_entry_point( const char *dll, const char *name, void *ret_addr )
182 {
183     EXCEPTION_RECORD rec;
184
185     rec.ExceptionCode           = EXCEPTION_WINE_STUB;
186     rec.ExceptionFlags          = EH_NONCONTINUABLE;
187     rec.ExceptionRecord         = NULL;
188     rec.ExceptionAddress        = ret_addr;
189     rec.NumberParameters        = 2;
190     rec.ExceptionInformation[0] = (ULONG_PTR)dll;
191     rec.ExceptionInformation[1] = (ULONG_PTR)name;
192     for (;;) RtlRaiseException( &rec );
193 }
194
195
196 #include "pshpack1.h"
197 #ifdef __i386__
198 struct stub
199 {
200     BYTE        pushl1;     /* pushl $name */
201     const char *name;
202     BYTE        pushl2;     /* pushl $dll */
203     const char *dll;
204     BYTE        call;       /* call stub_entry_point */
205     DWORD       entry;
206 };
207 #else
208 struct stub
209 {
210     BYTE movq_rdi[2];      /* movq $dll,%rdi */
211     const char *dll;
212     BYTE movq_rsi[2];      /* movq $name,%rsi */
213     const char *name;
214     BYTE movq_rsp_rdx[4];  /* movq (%rsp),%rdx */
215     BYTE movq_rax[2];      /* movq $entry, %rax */
216     const void* entry;
217     BYTE jmpq_rax[2];      /* jmp %rax */
218 };
219 #endif
220 #include "poppack.h"
221
222 /*************************************************************************
223  *              allocate_stub
224  *
225  * Allocate a stub entry point.
226  */
227 static ULONG_PTR allocate_stub( const char *dll, const char *name )
228 {
229 #define MAX_SIZE 65536
230     static struct stub *stubs;
231     static unsigned int nb_stubs;
232     struct stub *stub;
233
234     if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
235
236     if (!stubs)
237     {
238         SIZE_T size = MAX_SIZE;
239         if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
240                                      MEM_COMMIT, PAGE_EXECUTE_WRITECOPY ) != STATUS_SUCCESS)
241             return 0xdeadbeef;
242     }
243     stub = &stubs[nb_stubs++];
244 #ifdef __i386__
245     stub->pushl1    = 0x68;  /* pushl $name */
246     stub->name      = name;
247     stub->pushl2    = 0x68;  /* pushl $dll */
248     stub->dll       = dll;
249     stub->call      = 0xe8;  /* call stub_entry_point */
250     stub->entry     = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
251 #else
252     stub->movq_rdi[0]     = 0x48;  /* movq $dll,%rdi */
253     stub->movq_rdi[1]     = 0xbf;
254     stub->dll             = dll;
255     stub->movq_rsi[0]     = 0x48;  /* movq $name,%rsi */
256     stub->movq_rsi[1]     = 0xbe;
257     stub->name            = name;
258     stub->movq_rsp_rdx[0] = 0x48;  /* movq (%rsp),%rdx */
259     stub->movq_rsp_rdx[1] = 0x8b;
260     stub->movq_rsp_rdx[2] = 0x14;
261     stub->movq_rsp_rdx[3] = 0x24;
262     stub->movq_rax[0]     = 0x48;  /* movq $entry, %rax */
263     stub->movq_rax[1]     = 0xb8;
264     stub->entry           = stub_entry_point;
265     stub->jmpq_rax[0]     = 0xff;  /* jmp %rax */
266     stub->jmpq_rax[1]     = 0xe0;
267 #endif
268     return (ULONG_PTR)stub;
269 }
270
271 #else  /* __i386__ */
272 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
273 #endif  /* __i386__ */
274
275
276 /*************************************************************************
277  *              get_modref
278  *
279  * Looks for the referenced HMODULE in the current process
280  * The loader_section must be locked while calling this function.
281  */
282 static WINE_MODREF *get_modref( HMODULE hmod )
283 {
284     PLIST_ENTRY mark, entry;
285     PLDR_MODULE mod;
286
287     if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
288
289     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
290     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
291     {
292         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
293         if (mod->BaseAddress == hmod)
294             return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
295         if (mod->BaseAddress > (void*)hmod) break;
296     }
297     return NULL;
298 }
299
300
301 /**********************************************************************
302  *          find_basename_module
303  *
304  * Find a module from its base name.
305  * The loader_section must be locked while calling this function
306  */
307 static WINE_MODREF *find_basename_module( LPCWSTR name )
308 {
309     PLIST_ENTRY mark, entry;
310
311     if (cached_modref && !strcmpiW( name, cached_modref->ldr.BaseDllName.Buffer ))
312         return cached_modref;
313
314     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
315     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
316     {
317         LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
318         if (!strcmpiW( name, mod->BaseDllName.Buffer ))
319         {
320             cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
321             return cached_modref;
322         }
323     }
324     return NULL;
325 }
326
327
328 /**********************************************************************
329  *          find_fullname_module
330  *
331  * Find a module from its full path name.
332  * The loader_section must be locked while calling this function
333  */
334 static WINE_MODREF *find_fullname_module( LPCWSTR name )
335 {
336     PLIST_ENTRY mark, entry;
337
338     if (cached_modref && !strcmpiW( name, cached_modref->ldr.FullDllName.Buffer ))
339         return cached_modref;
340
341     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
342     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
343     {
344         LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
345         if (!strcmpiW( name, mod->FullDllName.Buffer ))
346         {
347             cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
348             return cached_modref;
349         }
350     }
351     return NULL;
352 }
353
354
355 /*************************************************************************
356  *              find_forwarded_export
357  *
358  * Find the final function pointer for a forwarded function.
359  * The loader_section must be locked while calling this function.
360  */
361 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
362 {
363     const IMAGE_EXPORT_DIRECTORY *exports;
364     DWORD exp_size;
365     WINE_MODREF *wm;
366     WCHAR mod_name[32];
367     const char *end = strrchr(forward, '.');
368     FARPROC proc = NULL;
369
370     if (!end) return NULL;
371     if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name)) return NULL;
372     ascii_to_unicode( mod_name, forward, end - forward );
373     mod_name[end - forward] = 0;
374     if (!strchrW( mod_name, '.' ))
375     {
376         if ((end - forward) * sizeof(WCHAR) >= sizeof(mod_name) - sizeof(dllW)) return NULL;
377         memcpy( mod_name + (end - forward), dllW, sizeof(dllW) );
378     }
379
380     if (!(wm = find_basename_module( mod_name )))
381     {
382         TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
383         if (load_dll( load_path, mod_name, 0, &wm ) == STATUS_SUCCESS &&
384             !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
385         {
386             if (process_attach( wm, NULL ) != STATUS_SUCCESS)
387             {
388                 LdrUnloadDll( wm->ldr.BaseAddress );
389                 wm = NULL;
390             }
391         }
392
393         if (!wm)
394         {
395             ERR( "module not found for forward '%s' used by %s\n",
396                  forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer) );
397             return NULL;
398         }
399     }
400     if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
401                                                  IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
402         proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1, load_path );
403
404     if (!proc)
405     {
406         ERR("function not found for forward '%s' used by %s."
407             " If you are using builtin %s, try using the native one instead.\n",
408             forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
409             debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
410     }
411     return proc;
412 }
413
414
415 /*************************************************************************
416  *              find_ordinal_export
417  *
418  * Find an exported function by ordinal.
419  * The exports base must have been subtracted from the ordinal already.
420  * The loader_section must be locked while calling this function.
421  */
422 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
423                                     DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
424 {
425     FARPROC proc;
426     const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
427
428     if (ordinal >= exports->NumberOfFunctions)
429     {
430         TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
431         return NULL;
432     }
433     if (!functions[ordinal]) return NULL;
434
435     proc = get_rva( module, functions[ordinal] );
436
437     /* if the address falls into the export dir, it's a forward */
438     if (((const char *)proc >= (const char *)exports) && 
439         ((const char *)proc < (const char *)exports + exp_size))
440         return find_forwarded_export( module, (const char *)proc, load_path );
441
442     if (TRACE_ON(snoop))
443     {
444         const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
445         proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
446     }
447     if (TRACE_ON(relay))
448     {
449         const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
450         proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
451     }
452     return proc;
453 }
454
455
456 /*************************************************************************
457  *              find_named_export
458  *
459  * Find an exported function by name.
460  * The loader_section must be locked while calling this function.
461  */
462 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
463                                   DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
464 {
465     const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
466     const DWORD *names = get_rva( module, exports->AddressOfNames );
467     int min = 0, max = exports->NumberOfNames - 1;
468
469     /* first check the hint */
470     if (hint >= 0 && hint <= max)
471     {
472         char *ename = get_rva( module, names[hint] );
473         if (!strcmp( ename, name ))
474             return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
475     }
476
477     /* then do a binary search */
478     while (min <= max)
479     {
480         int res, pos = (min + max) / 2;
481         char *ename = get_rva( module, names[pos] );
482         if (!(res = strcmp( ename, name )))
483             return find_ordinal_export( module, exports, exp_size, ordinals[pos], load_path );
484         if (res > 0) max = pos - 1;
485         else min = pos + 1;
486     }
487     return NULL;
488
489 }
490
491
492 /*************************************************************************
493  *              import_dll
494  *
495  * Import the dll specified by the given import descriptor.
496  * The loader_section must be locked while calling this function.
497  */
498 static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
499 {
500     NTSTATUS status;
501     WINE_MODREF *wmImp;
502     HMODULE imp_mod;
503     const IMAGE_EXPORT_DIRECTORY *exports;
504     DWORD exp_size;
505     const IMAGE_THUNK_DATA *import_list;
506     IMAGE_THUNK_DATA *thunk_list;
507     WCHAR buffer[32];
508     const char *name = get_rva( module, descr->Name );
509     DWORD len = strlen(name);
510     PVOID protect_base;
511     SIZE_T protect_size = 0;
512     DWORD protect_old;
513
514     thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
515     if (descr->u.OriginalFirstThunk)
516         import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
517     else
518         import_list = thunk_list;
519
520     while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */
521
522     if (len * sizeof(WCHAR) < sizeof(buffer))
523     {
524         ascii_to_unicode( buffer, name, len );
525         buffer[len] = 0;
526         status = load_dll( load_path, buffer, 0, &wmImp );
527     }
528     else  /* need to allocate a larger buffer */
529     {
530         WCHAR *ptr = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
531         if (!ptr) return NULL;
532         ascii_to_unicode( ptr, name, len );
533         ptr[len] = 0;
534         status = load_dll( load_path, ptr, 0, &wmImp );
535         RtlFreeHeap( GetProcessHeap(), 0, ptr );
536     }
537
538     if (status)
539     {
540         if (status == STATUS_DLL_NOT_FOUND)
541             ERR("Library %s (which is needed by %s) not found\n",
542                 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
543         else
544             ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
545                 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
546         return NULL;
547     }
548
549     /* unprotect the import address table since it can be located in
550      * readonly section */
551     while (import_list[protect_size].u1.Ordinal) protect_size++;
552     protect_base = thunk_list;
553     protect_size *= sizeof(*thunk_list);
554     NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
555                             &protect_size, PAGE_WRITECOPY, &protect_old );
556
557     imp_mod = wmImp->ldr.BaseAddress;
558     exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
559
560     if (!exports)
561     {
562         /* set all imported function to deadbeef */
563         while (import_list->u1.Ordinal)
564         {
565             if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
566             {
567                 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
568                 WARN("No implementation for %s.%d", name, ordinal );
569                 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
570             }
571             else
572             {
573                 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
574                 WARN("No implementation for %s.%s", name, pe_name->Name );
575                 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
576             }
577             WARN(" imported from %s, allocating stub %p\n",
578                  debugstr_w(current_modref->ldr.FullDllName.Buffer),
579                  (void *)thunk_list->u1.Function );
580             import_list++;
581             thunk_list++;
582         }
583         goto done;
584     }
585
586     while (import_list->u1.Ordinal)
587     {
588         if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
589         {
590             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
591
592             thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
593                                                                       ordinal - exports->Base, load_path );
594             if (!thunk_list->u1.Function)
595             {
596                 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
597                 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
598                      name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
599                      (void *)thunk_list->u1.Function );
600             }
601             TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
602         }
603         else  /* import by name */
604         {
605             IMAGE_IMPORT_BY_NAME *pe_name;
606             pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
607             thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
608                                                                     (const char*)pe_name->Name,
609                                                                     pe_name->Hint, load_path );
610             if (!thunk_list->u1.Function)
611             {
612                 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
613                 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
614                      name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
615                      (void *)thunk_list->u1.Function );
616             }
617             TRACE_(imports)("--- %s %s.%d = %p\n",
618                             pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
619         }
620         import_list++;
621         thunk_list++;
622     }
623
624 done:
625     /* restore old protection of the import address table */
626     NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
627     return wmImp;
628 }
629
630
631 /***********************************************************************
632  *           create_module_activation_context
633  */
634 static NTSTATUS create_module_activation_context( LDR_MODULE *module )
635 {
636     NTSTATUS status;
637     LDR_RESOURCE_INFO info;
638     const IMAGE_RESOURCE_DATA_ENTRY *entry;
639
640     info.Type = RT_MANIFEST;
641     info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
642     info.Language = 0;
643     if (!(status = LdrFindResource_U( module->BaseAddress, &info, 3, &entry )))
644     {
645         ACTCTXW ctx;
646         ctx.cbSize   = sizeof(ctx);
647         ctx.lpSource = NULL;
648         ctx.dwFlags  = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
649         ctx.hModule  = module->BaseAddress;
650         ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
651         status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
652     }
653     return status;
654 }
655
656
657 /****************************************************************
658  *       fixup_imports
659  *
660  * Fixup all imports of a given module.
661  * The loader_section must be locked while calling this function.
662  */
663 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
664 {
665     int i, nb_imports;
666     const IMAGE_IMPORT_DESCRIPTOR *imports;
667     WINE_MODREF *prev;
668     DWORD size;
669     NTSTATUS status;
670     ULONG_PTR cookie;
671
672     if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
673     wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
674
675     if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
676                                                   IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
677         return STATUS_SUCCESS;
678
679     nb_imports = 0;
680     while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
681
682     if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
683
684     if (!create_module_activation_context( &wm->ldr ))
685         RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
686
687     /* Allocate module dependency list */
688     wm->nDeps = nb_imports;
689     wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
690
691     /* load the imported modules. They are automatically
692      * added to the modref list of the process.
693      */
694     prev = current_modref;
695     current_modref = wm;
696     status = STATUS_SUCCESS;
697     for (i = 0; i < nb_imports; i++)
698     {
699         if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
700             status = STATUS_DLL_NOT_FOUND;
701     }
702     current_modref = prev;
703     if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
704     return status;
705 }
706
707
708 /*************************************************************************
709  *              is_dll_native_subsystem
710  *
711  * Check if dll is a proper native driver.
712  * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
713  * while being perfectly normal DLLs.  This heuristic should catch such breakages.
714  */
715 static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
716 {
717     static const WCHAR ntdllW[]    = {'n','t','d','l','l','.','d','l','l',0};
718     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
719     const IMAGE_IMPORT_DESCRIPTOR *imports;
720     DWORD i, size;
721     WCHAR buffer[16];
722
723     if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
724     if (nt->OptionalHeader.SectionAlignment < getpagesize()) return TRUE;
725
726     if ((imports = RtlImageDirectoryEntryToData( module, TRUE,
727                                                  IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
728     {
729         for (i = 0; imports[i].Name; i++)
730         {
731             const char *name = get_rva( module, imports[i].Name );
732             DWORD len = strlen(name);
733             if (len * sizeof(WCHAR) >= sizeof(buffer)) continue;
734             ascii_to_unicode( buffer, name, len + 1 );
735             if (!strcmpiW( buffer, ntdllW ) || !strcmpiW( buffer, kernel32W ))
736             {
737                 TRACE( "%s imports %s, assuming not native\n", debugstr_w(filename), debugstr_w(buffer) );
738                 return FALSE;
739             }
740         }
741     }
742     return TRUE;
743 }
744
745
746 /*************************************************************************
747  *              alloc_module
748  *
749  * Allocate a WINE_MODREF structure and add it to the process list
750  * The loader_section must be locked while calling this function.
751  */
752 static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
753 {
754     WINE_MODREF *wm;
755     const WCHAR *p;
756     const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
757     PLIST_ENTRY entry, mark;
758
759     if (!(wm = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*wm) ))) return NULL;
760
761     wm->nDeps    = 0;
762     wm->deps     = NULL;
763
764     wm->ldr.BaseAddress   = hModule;
765     wm->ldr.EntryPoint    = NULL;
766     wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
767     wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
768     wm->ldr.LoadCount     = 1;
769     wm->ldr.TlsIndex      = -1;
770     wm->ldr.SectionHandle = NULL;
771     wm->ldr.CheckSum      = 0;
772     wm->ldr.TimeDateStamp = 0;
773     wm->ldr.ActivationContext = 0;
774
775     RtlCreateUnicodeString( &wm->ldr.FullDllName, filename );
776     if ((p = strrchrW( wm->ldr.FullDllName.Buffer, '\\' ))) p++;
777     else p = wm->ldr.FullDllName.Buffer;
778     RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
779
780     if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
781     {
782         wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
783         if (nt->OptionalHeader.AddressOfEntryPoint)
784             wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
785     }
786
787     InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
788                    &wm->ldr.InLoadOrderModuleList);
789
790     /* insert module in MemoryList, sorted in increasing base addresses */
791     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
792     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
793     {
794         if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
795             break;
796     }
797     entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
798     wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
799     wm->ldr.InMemoryOrderModuleList.Flink = entry;
800     entry->Blink = &wm->ldr.InMemoryOrderModuleList;
801
802     /* wait until init is called for inserting into this list */
803     wm->ldr.InInitializationOrderModuleList.Flink = NULL;
804     wm->ldr.InInitializationOrderModuleList.Blink = NULL;
805
806     if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
807     {
808         WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
809         VIRTUAL_SetForceExec( TRUE );
810     }
811     return wm;
812 }
813
814
815 /*************************************************************************
816  *              alloc_process_tls
817  *
818  * Allocate the process-wide structure for module TLS storage.
819  */
820 static NTSTATUS alloc_process_tls(void)
821 {
822     PLIST_ENTRY mark, entry;
823     PLDR_MODULE mod;
824     const IMAGE_TLS_DIRECTORY *dir;
825     ULONG size, i;
826
827     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
828     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
829     {
830         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
831         if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
832                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
833             continue;
834         size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
835         if (!size) continue;
836         tls_total_size += size;
837         tls_module_count++;
838     }
839     if (!tls_module_count) return STATUS_SUCCESS;
840
841     TRACE( "count %u size %u\n", tls_module_count, tls_total_size );
842
843     tls_dirs = RtlAllocateHeap( GetProcessHeap(), 0, tls_module_count * sizeof(*tls_dirs) );
844     if (!tls_dirs) return STATUS_NO_MEMORY;
845
846     for (i = 0, entry = mark->Flink; entry != mark; entry = entry->Flink)
847     {
848         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
849         if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
850                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
851             continue;
852         tls_dirs[i] = dir;
853         *(DWORD *)dir->AddressOfIndex = i;
854         mod->TlsIndex = i;
855         mod->LoadCount = -1;  /* can't unload it */
856         i++;
857     }
858     return STATUS_SUCCESS;
859 }
860
861
862 /*************************************************************************
863  *              alloc_thread_tls
864  *
865  * Allocate the per-thread structure for module TLS storage.
866  */
867 static NTSTATUS alloc_thread_tls(void)
868 {
869     void **pointers;
870     char *data;
871     UINT i;
872
873     if (!tls_module_count) return STATUS_SUCCESS;
874
875     if (!(pointers = RtlAllocateHeap( GetProcessHeap(), 0,
876                                       tls_module_count * sizeof(*pointers) )))
877         return STATUS_NO_MEMORY;
878
879     if (!(data = RtlAllocateHeap( GetProcessHeap(), 0, tls_total_size )))
880     {
881         RtlFreeHeap( GetProcessHeap(), 0, pointers );
882         return STATUS_NO_MEMORY;
883     }
884
885     for (i = 0; i < tls_module_count; i++)
886     {
887         const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
888         ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
889
890         TRACE( "thread %04x idx %d: %d/%d bytes from %p to %p\n",
891                GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
892                (void *)dir->StartAddressOfRawData, data );
893
894         pointers[i] = data;
895         memcpy( data, (void *)dir->StartAddressOfRawData, size );
896         data += size;
897         memset( data, 0, dir->SizeOfZeroFill );
898         data += dir->SizeOfZeroFill;
899     }
900     NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
901     return STATUS_SUCCESS;
902 }
903
904
905 /*************************************************************************
906  *              call_tls_callbacks
907  */
908 static void call_tls_callbacks( HMODULE module, UINT reason )
909 {
910     const IMAGE_TLS_DIRECTORY *dir;
911     const PIMAGE_TLS_CALLBACK *callback;
912     ULONG dirsize;
913
914     dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
915     if (!dir || !dir->AddressOfCallBacks) return;
916
917     for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
918     {
919         if (TRACE_ON(relay))
920             DPRINTF("%04x:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
921                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
922         __TRY
923         {
924             (*callback)( module, reason, NULL );
925         }
926         __EXCEPT_ALL
927         {
928             if (TRACE_ON(relay))
929                 DPRINTF("%04x:exception in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
930                         GetCurrentThreadId(), callback, module, reason_names[reason] );
931             return;
932         }
933         __ENDTRY
934         if (TRACE_ON(relay))
935             DPRINTF("%04x:Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
936                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
937     }
938 }
939
940
941 /*************************************************************************
942  *              MODULE_InitDLL
943  */
944 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
945 {
946     WCHAR mod_name[32];
947     NTSTATUS status = STATUS_SUCCESS;
948     DLLENTRYPROC entry = wm->ldr.EntryPoint;
949     void *module = wm->ldr.BaseAddress;
950     BOOL retv = TRUE;
951
952     /* Skip calls for modules loaded with special load flags */
953
954     if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
955     if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
956     if (!entry) return STATUS_SUCCESS;
957
958     if (TRACE_ON(relay))
959     {
960         size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
961         memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
962         mod_name[len / sizeof(WCHAR)] = 0;
963         DPRINTF("%04x:Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
964                 GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
965                 reason_names[reason], lpReserved );
966     }
967     else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
968                reason_names[reason], lpReserved );
969
970     __TRY
971     {
972         retv = call_dll_entry_point( entry, module, reason, lpReserved );
973         if (!retv)
974             status = STATUS_DLL_INIT_FAILED;
975     }
976     __EXCEPT_ALL
977     {
978         if (TRACE_ON(relay))
979             DPRINTF("%04x:exception in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
980                     GetCurrentThreadId(), entry, module, reason_names[reason], lpReserved );
981         status = GetExceptionCode();
982     }
983     __ENDTRY
984
985     /* The state of the module list may have changed due to the call
986        to the dll. We cannot assume that this module has not been
987        deleted.  */
988     if (TRACE_ON(relay))
989         DPRINTF("%04x:Ret  PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
990                 GetCurrentThreadId(), entry, module, debugstr_w(mod_name),
991                 reason_names[reason], lpReserved, retv );
992     else TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
993
994     return status;
995 }
996
997
998 /*************************************************************************
999  *              process_attach
1000  *
1001  * Send the process attach notification to all DLLs the given module
1002  * depends on (recursively). This is somewhat complicated due to the fact that
1003  *
1004  * - we have to respect the module dependencies, i.e. modules implicitly
1005  *   referenced by another module have to be initialized before the module
1006  *   itself can be initialized
1007  *
1008  * - the initialization routine of a DLL can itself call LoadLibrary,
1009  *   thereby introducing a whole new set of dependencies (even involving
1010  *   the 'old' modules) at any time during the whole process
1011  *
1012  * (Note that this routine can be recursively entered not only directly
1013  *  from itself, but also via LoadLibrary from one of the called initialization
1014  *  routines.)
1015  *
1016  * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1017  * the process *detach* notifications to be sent in the correct order.
1018  * This must not only take into account module dependencies, but also
1019  * 'hidden' dependencies created by modules calling LoadLibrary in their
1020  * attach notification routine.
1021  *
1022  * The strategy is rather simple: we move a WINE_MODREF to the head of the
1023  * list after the attach notification has returned.  This implies that the
1024  * detach notifications are called in the reverse of the sequence the attach
1025  * notifications *returned*.
1026  *
1027  * The loader_section must be locked while calling this function.
1028  */
1029 static NTSTATUS process_attach( WINE_MODREF *wm, LPVOID lpReserved )
1030 {
1031     NTSTATUS status = STATUS_SUCCESS;
1032     ULONG_PTR cookie;
1033     int i;
1034
1035     if (process_detaching) return status;
1036
1037     /* prevent infinite recursion in case of cyclical dependencies */
1038     if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1039          || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1040         return status;
1041
1042     TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1043
1044     /* Tag current MODREF to prevent recursive loop */
1045     wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1046     if (lpReserved) wm->ldr.LoadCount = -1;  /* pin it if imported by the main exe */
1047     if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1048
1049     /* Recursively attach all DLLs this one depends on */
1050     for ( i = 0; i < wm->nDeps; i++ )
1051     {
1052         if (!wm->deps[i]) continue;
1053         if ((status = process_attach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
1054     }
1055
1056     /* Call DLL entry point */
1057     if (status == STATUS_SUCCESS)
1058     {
1059         WINE_MODREF *prev = current_modref;
1060         current_modref = wm;
1061         status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1062         if (status == STATUS_SUCCESS)
1063             wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1064         else
1065         {
1066             /* point to the name so LdrInitializeThunk can print it */
1067             last_failed_modref = wm;
1068             WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1069         }
1070         current_modref = prev;
1071     }
1072
1073     if (!wm->ldr.InInitializationOrderModuleList.Flink)
1074         InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1075                        &wm->ldr.InInitializationOrderModuleList);
1076
1077     if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1078     /* Remove recursion flag */
1079     wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1080
1081     TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1082     return status;
1083 }
1084
1085
1086 /**********************************************************************
1087  *          attach_implicitly_loaded_dlls
1088  *
1089  * Attach to the (builtin) dlls that have been implicitly loaded because
1090  * of a dependency at the Unix level, but not imported at the Win32 level.
1091  */
1092 static void attach_implicitly_loaded_dlls( LPVOID reserved )
1093 {
1094     for (;;)
1095     {
1096         PLIST_ENTRY mark, entry;
1097
1098         mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
1099         for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1100         {
1101             LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
1102
1103             if (mod->Flags & (LDR_LOAD_IN_PROGRESS | LDR_PROCESS_ATTACHED)) continue;
1104             TRACE( "found implicitly loaded %s, attaching to it\n",
1105                    debugstr_w(mod->BaseDllName.Buffer));
1106             process_attach( CONTAINING_RECORD(mod, WINE_MODREF, ldr), reserved );
1107             break;  /* restart the search from the start */
1108         }
1109         if (entry == mark) break;  /* nothing found */
1110     }
1111 }
1112
1113
1114 /*************************************************************************
1115  *              process_detach
1116  *
1117  * Send DLL process detach notifications.  See the comment about calling
1118  * sequence at process_attach.  Unless the bForceDetach flag
1119  * is set, only DLLs with zero refcount are notified.
1120  */
1121 static void process_detach( BOOL bForceDetach, LPVOID lpReserved )
1122 {
1123     PLIST_ENTRY mark, entry;
1124     PLDR_MODULE mod;
1125
1126     RtlEnterCriticalSection( &loader_section );
1127     if (bForceDetach) process_detaching = 1;
1128     mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1129     do
1130     {
1131         for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1132         {
1133             mod = CONTAINING_RECORD(entry, LDR_MODULE, 
1134                                     InInitializationOrderModuleList);
1135             /* Check whether to detach this DLL */
1136             if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1137                 continue;
1138             if ( mod->LoadCount && !bForceDetach )
1139                 continue;
1140
1141             /* Call detach notification */
1142             mod->Flags &= ~LDR_PROCESS_ATTACHED;
1143             MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
1144                             DLL_PROCESS_DETACH, lpReserved );
1145
1146             /* Restart at head of WINE_MODREF list, as entries might have
1147                been added and/or removed while performing the call ... */
1148             break;
1149         }
1150     } while (entry != mark);
1151
1152     RtlLeaveCriticalSection( &loader_section );
1153 }
1154
1155 /*************************************************************************
1156  *              MODULE_DllThreadAttach
1157  *
1158  * Send DLL thread attach notifications. These are sent in the
1159  * reverse sequence of process detach notification.
1160  *
1161  */
1162 NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
1163 {
1164     PLIST_ENTRY mark, entry;
1165     PLDR_MODULE mod;
1166     NTSTATUS    status;
1167
1168     /* don't do any attach calls if process is exiting */
1169     if (process_detaching) return STATUS_SUCCESS;
1170     /* FIXME: there is still a race here */
1171
1172     RtlEnterCriticalSection( &loader_section );
1173
1174     if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
1175
1176     mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1177     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1178     {
1179         mod = CONTAINING_RECORD(entry, LDR_MODULE, 
1180                                 InInitializationOrderModuleList);
1181         if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1182             continue;
1183         if ( mod->Flags & LDR_NO_DLL_CALLS )
1184             continue;
1185
1186         MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1187                         DLL_THREAD_ATTACH, lpReserved );
1188     }
1189
1190 done:
1191     RtlLeaveCriticalSection( &loader_section );
1192     return status;
1193 }
1194
1195 /******************************************************************
1196  *              LdrDisableThreadCalloutsForDll (NTDLL.@)
1197  *
1198  */
1199 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1200 {
1201     WINE_MODREF *wm;
1202     NTSTATUS    ret = STATUS_SUCCESS;
1203
1204     RtlEnterCriticalSection( &loader_section );
1205
1206     wm = get_modref( hModule );
1207     if (!wm || wm->ldr.TlsIndex != -1)
1208         ret = STATUS_DLL_NOT_FOUND;
1209     else
1210         wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1211
1212     RtlLeaveCriticalSection( &loader_section );
1213
1214     return ret;
1215 }
1216
1217 /******************************************************************
1218  *              LdrFindEntryForAddress (NTDLL.@)
1219  *
1220  * The loader_section must be locked while calling this function
1221  */
1222 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
1223 {
1224     PLIST_ENTRY mark, entry;
1225     PLDR_MODULE mod;
1226
1227     mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1228     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1229     {
1230         mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
1231         if ((const void *)mod->BaseAddress <= addr &&
1232             (const char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
1233         {
1234             *pmod = mod;
1235             return STATUS_SUCCESS;
1236         }
1237         if ((const void *)mod->BaseAddress > addr) break;
1238     }
1239     return STATUS_NO_MORE_ENTRIES;
1240 }
1241
1242 /******************************************************************
1243  *              LdrLockLoaderLock  (NTDLL.@)
1244  *
1245  * Note: flags are not implemented.
1246  * Flag 0x01 is used to raise exceptions on errors.
1247  * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
1248  */
1249 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
1250 {
1251     if (flags) FIXME( "flags %x not supported\n", flags );
1252
1253     if (result) *result = 1;
1254     if (!magic) return STATUS_INVALID_PARAMETER_3;
1255     RtlEnterCriticalSection( &loader_section );
1256     *magic = GetCurrentThreadId();
1257     return STATUS_SUCCESS;
1258 }
1259
1260
1261 /******************************************************************
1262  *              LdrUnlockLoaderUnlock  (NTDLL.@)
1263  */
1264 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
1265 {
1266     if (magic)
1267     {
1268         if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1269         RtlLeaveCriticalSection( &loader_section );
1270     }
1271     return STATUS_SUCCESS;
1272 }
1273
1274
1275 /******************************************************************
1276  *              LdrGetProcedureAddress  (NTDLL.@)
1277  */
1278 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
1279                                        ULONG ord, PVOID *address)
1280 {
1281     IMAGE_EXPORT_DIRECTORY *exports;
1282     DWORD exp_size;
1283     NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1284
1285     RtlEnterCriticalSection( &loader_section );
1286
1287     /* check if the module itself is invalid to return the proper error */
1288     if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
1289     else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
1290                                                       IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1291     {
1292         LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1293         void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, load_path )
1294                           : find_ordinal_export( module, exports, exp_size, ord - exports->Base, load_path );
1295         if (proc)
1296         {
1297             *address = proc;
1298             ret = STATUS_SUCCESS;
1299         }
1300     }
1301
1302     RtlLeaveCriticalSection( &loader_section );
1303     return ret;
1304 }
1305
1306
1307 /***********************************************************************
1308  *           is_fake_dll
1309  *
1310  * Check if a loaded native dll is a Wine fake dll.
1311  */
1312 static BOOL is_fake_dll( HANDLE handle )
1313 {
1314     static const char fakedll_signature[] = "Wine placeholder DLL";
1315     char buffer[sizeof(IMAGE_DOS_HEADER) + sizeof(fakedll_signature)];
1316     const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)buffer;
1317     IO_STATUS_BLOCK io;
1318     LARGE_INTEGER offset;
1319
1320     offset.QuadPart = 0;
1321     if (NtReadFile( handle, 0, NULL, 0, &io, buffer, sizeof(buffer), &offset, NULL )) return FALSE;
1322     if (io.Information < sizeof(buffer)) return FALSE;
1323     if (dos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
1324     if (dos->e_lfanew >= sizeof(*dos) + sizeof(fakedll_signature) &&
1325         !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )) return TRUE;
1326     return FALSE;
1327 }
1328
1329
1330 /***********************************************************************
1331  *           get_builtin_fullname
1332  *
1333  * Build the full pathname for a builtin dll.
1334  */
1335 static WCHAR *get_builtin_fullname( const WCHAR *path, const char *filename )
1336 {
1337     static const WCHAR soW[] = {'.','s','o',0};
1338     WCHAR *p, *fullname;
1339     size_t i, len = strlen(filename);
1340
1341     /* check if path can correspond to the dll we have */
1342     if (path && (p = strrchrW( path, '\\' )))
1343     {
1344         p++;
1345         for (i = 0; i < len; i++)
1346             if (tolowerW(p[i]) != tolowerW( (WCHAR)filename[i]) ) break;
1347         if (i == len && (!p[len] || !strcmpiW( p + len, soW )))
1348         {
1349             /* the filename matches, use path as the full path */
1350             len += p - path;
1351             if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
1352             {
1353                 memcpy( fullname, path, len * sizeof(WCHAR) );
1354                 fullname[len] = 0;
1355             }
1356             return fullname;
1357         }
1358     }
1359
1360     if ((fullname = RtlAllocateHeap( GetProcessHeap(), 0,
1361                                      system_dir.MaximumLength + (len + 1) * sizeof(WCHAR) )))
1362     {
1363         memcpy( fullname, system_dir.Buffer, system_dir.Length );
1364         p = fullname + system_dir.Length / sizeof(WCHAR);
1365         if (p > fullname && p[-1] != '\\') *p++ = '\\';
1366         ascii_to_unicode( p, filename, len + 1 );
1367     }
1368     return fullname;
1369 }
1370
1371
1372 /***********************************************************************
1373  *           load_builtin_callback
1374  *
1375  * Load a library in memory; callback function for wine_dll_register
1376  */
1377 static void load_builtin_callback( void *module, const char *filename )
1378 {
1379     static const WCHAR emptyW[1];
1380     IMAGE_NT_HEADERS *nt;
1381     WINE_MODREF *wm;
1382     WCHAR *fullname;
1383     const WCHAR *load_path;
1384
1385     if (!module)
1386     {
1387         ERR("could not map image for %s\n", filename ? filename : "main exe" );
1388         return;
1389     }
1390     if (!(nt = RtlImageNtHeader( module )))
1391     {
1392         ERR( "bad module for %s\n", filename ? filename : "main exe" );
1393         builtin_load_info->status = STATUS_INVALID_IMAGE_FORMAT;
1394         return;
1395     }
1396     virtual_create_system_view( module, nt->OptionalHeader.SizeOfImage,
1397                                 VPROT_SYSTEM | VPROT_IMAGE | VPROT_COMMITTED |
1398                                 VPROT_READ | VPROT_WRITECOPY | VPROT_EXEC );
1399
1400     /* create the MODREF */
1401
1402     if (!(fullname = get_builtin_fullname( builtin_load_info->filename, filename )))
1403     {
1404         ERR( "can't load %s\n", filename );
1405         builtin_load_info->status = STATUS_NO_MEMORY;
1406         return;
1407     }
1408
1409     wm = alloc_module( module, fullname );
1410     RtlFreeHeap( GetProcessHeap(), 0, fullname );
1411     if (!wm)
1412     {
1413         ERR( "can't load %s\n", filename );
1414         builtin_load_info->status = STATUS_NO_MEMORY;
1415         return;
1416     }
1417     wm->ldr.Flags |= LDR_WINE_INTERNAL;
1418
1419     if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
1420         !NtCurrentTeb()->Peb->ImageBaseAddress)  /* if we already have an executable, ignore this one */
1421     {
1422         NtCurrentTeb()->Peb->ImageBaseAddress = module;
1423     }
1424     else
1425     {
1426         /* fixup imports */
1427
1428         load_path = builtin_load_info->load_path;
1429         if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
1430         if (!load_path) load_path = emptyW;
1431         if (fixup_imports( wm, load_path ) != STATUS_SUCCESS)
1432         {
1433             /* the module has only be inserted in the load & memory order lists */
1434             RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
1435             RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
1436             /* FIXME: free the modref */
1437             builtin_load_info->status = STATUS_DLL_NOT_FOUND;
1438             return;
1439         }
1440     }
1441
1442     builtin_load_info->wm = wm;
1443     TRACE( "loaded %s %p %p\n", filename, wm, module );
1444
1445     /* send the DLL load event */
1446
1447     SERVER_START_REQ( load_dll )
1448     {
1449         req->handle     = 0;
1450         req->base       = wine_server_client_ptr( module );
1451         req->size       = nt->OptionalHeader.SizeOfImage;
1452         req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
1453         req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1454         req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1455         wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1456         wine_server_call( req );
1457     }
1458     SERVER_END_REQ;
1459
1460     /* setup relay debugging entry points */
1461     if (TRACE_ON(relay)) RELAY_SetupDLL( module );
1462 }
1463
1464
1465 /******************************************************************************
1466  *      load_native_dll  (internal)
1467  */
1468 static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
1469                                  DWORD flags, WINE_MODREF** pwm )
1470 {
1471     void *module;
1472     HANDLE mapping;
1473     OBJECT_ATTRIBUTES attr;
1474     LARGE_INTEGER size;
1475     IMAGE_NT_HEADERS *nt;
1476     SIZE_T len = 0;
1477     WINE_MODREF *wm;
1478     NTSTATUS status;
1479
1480     TRACE("Trying native dll %s\n", debugstr_w(name));
1481
1482     attr.Length                   = sizeof(attr);
1483     attr.RootDirectory            = 0;
1484     attr.ObjectName               = NULL;
1485     attr.Attributes               = 0;
1486     attr.SecurityDescriptor       = NULL;
1487     attr.SecurityQualityOfService = NULL;
1488     size.QuadPart = 0;
1489
1490     status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1491                               &attr, &size, PAGE_READONLY, SEC_IMAGE, file );
1492     if (status != STATUS_SUCCESS) return status;
1493
1494     module = NULL;
1495     status = NtMapViewOfSection( mapping, NtCurrentProcess(),
1496                                  &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
1497     NtClose( mapping );
1498     if (status != STATUS_SUCCESS) return status;
1499
1500     /* create the MODREF */
1501
1502     if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;
1503
1504     /* fixup imports */
1505
1506     if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
1507     {
1508         if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
1509         {
1510             /* the module has only be inserted in the load & memory order lists */
1511             RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
1512             RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
1513
1514             /* FIXME: there are several more dangling references
1515              * left. Including dlls loaded by this dll before the
1516              * failed one. Unrolling is rather difficult with the
1517              * current structure and we can leave them lying
1518              * around with no problems, so we don't care.
1519              * As these might reference our wm, we don't free it.
1520              */
1521             return status;
1522         }
1523     }
1524
1525     /* send DLL load event */
1526
1527     nt = RtlImageNtHeader( module );
1528
1529     SERVER_START_REQ( load_dll )
1530     {
1531         req->handle     = wine_server_obj_handle( file );
1532         req->base       = wine_server_client_ptr( module );
1533         req->size       = nt->OptionalHeader.SizeOfImage;
1534         req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
1535         req->dbg_size   = nt->FileHeader.NumberOfSymbols;
1536         req->name       = wine_server_client_ptr( &wm->ldr.FullDllName.Buffer );
1537         wine_server_add_data( req, wm->ldr.FullDllName.Buffer, wm->ldr.FullDllName.Length );
1538         wine_server_call( req );
1539     }
1540     SERVER_END_REQ;
1541
1542     if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( module );
1543
1544     TRACE_(loaddll)( "Loaded %s at %p: native\n", debugstr_w(wm->ldr.FullDllName.Buffer), module );
1545
1546     wm->ldr.LoadCount = 1;
1547     *pwm = wm;
1548     return STATUS_SUCCESS;
1549 }
1550
1551
1552 /***********************************************************************
1553  *           load_builtin_dll
1554  */
1555 static NTSTATUS load_builtin_dll( LPCWSTR load_path, LPCWSTR path, HANDLE file,
1556                                   DWORD flags, WINE_MODREF** pwm )
1557 {
1558     char error[256], dllname[MAX_PATH];
1559     const WCHAR *name, *p;
1560     DWORD len, i;
1561     void *handle = NULL;
1562     struct builtin_load_info info, *prev_info;
1563
1564     /* Fix the name in case we have a full path and extension */
1565     name = path;
1566     if ((p = strrchrW( name, '\\' ))) name = p + 1;
1567     if ((p = strrchrW( name, '/' ))) name = p + 1;
1568
1569     /* load_library will modify info.status. Note also that load_library can be
1570      * called several times, if the .so file we're loading has dependencies.
1571      * info.status will gather all the errors we may get while loading all these
1572      * libraries
1573      */
1574     info.load_path = load_path;
1575     info.filename  = NULL;
1576     info.status    = STATUS_SUCCESS;
1577     info.wm        = NULL;
1578
1579     if (file)  /* we have a real file, try to load it */
1580     {
1581         UNICODE_STRING nt_name;
1582         ANSI_STRING unix_name;
1583
1584         TRACE("Trying built-in %s\n", debugstr_w(path));
1585
1586         if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL ))
1587             return STATUS_DLL_NOT_FOUND;
1588
1589         if (wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE ))
1590         {
1591             RtlFreeUnicodeString( &nt_name );
1592             return STATUS_DLL_NOT_FOUND;
1593         }
1594         prev_info = builtin_load_info;
1595         info.filename = nt_name.Buffer + 4;  /* skip \??\ */
1596         builtin_load_info = &info;
1597         handle = wine_dlopen( unix_name.Buffer, RTLD_NOW, error, sizeof(error) );
1598         builtin_load_info = prev_info;
1599         RtlFreeUnicodeString( &nt_name );
1600         RtlFreeHeap( GetProcessHeap(), 0, unix_name.Buffer );
1601         if (!handle)
1602         {
1603             WARN( "failed to load .so lib for builtin %s: %s\n", debugstr_w(path), error );
1604             return STATUS_INVALID_IMAGE_FORMAT;
1605         }
1606     }
1607     else
1608     {
1609         int file_exists;
1610
1611         TRACE("Trying built-in %s\n", debugstr_w(name));
1612
1613         /* we don't want to depend on the current codepage here */
1614         len = strlenW( name ) + 1;
1615         if (len >= sizeof(dllname)) return STATUS_NAME_TOO_LONG;
1616         for (i = 0; i < len; i++)
1617         {
1618             if (name[i] > 127) return STATUS_DLL_NOT_FOUND;
1619             dllname[i] = (char)name[i];
1620             if (dllname[i] >= 'A' && dllname[i] <= 'Z') dllname[i] += 'a' - 'A';
1621         }
1622
1623         prev_info = builtin_load_info;
1624         builtin_load_info = &info;
1625         handle = wine_dll_load( dllname, error, sizeof(error), &file_exists );
1626         builtin_load_info = prev_info;
1627         if (!handle)
1628         {
1629             if (!file_exists)
1630             {
1631                 /* The file does not exist -> WARN() */
1632                 WARN("cannot open .so lib for builtin %s: %s\n", debugstr_w(name), error);
1633                 return STATUS_DLL_NOT_FOUND;
1634             }
1635             /* ERR() for all other errors (missing functions, ...) */
1636             ERR("failed to load .so lib for builtin %s: %s\n", debugstr_w(name), error );
1637             return STATUS_PROCEDURE_NOT_FOUND;
1638         }
1639     }
1640
1641     if (info.status != STATUS_SUCCESS)
1642     {
1643         wine_dll_unload( handle );
1644         return info.status;
1645     }
1646
1647     if (!info.wm)
1648     {
1649         PLIST_ENTRY mark, entry;
1650
1651         /* The constructor wasn't called, this means the .so is already
1652          * loaded under a different name. Try to find the wm for it. */
1653
1654         mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
1655         for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1656         {
1657             LDR_MODULE *mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
1658             if (mod->Flags & LDR_WINE_INTERNAL && mod->SectionHandle == handle)
1659             {
1660                 info.wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
1661                 TRACE( "Found %s at %p for builtin %s\n",
1662                        debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress, debugstr_w(path) );
1663                 break;
1664             }
1665         }
1666         wine_dll_unload( handle );  /* release the libdl refcount */
1667         if (!info.wm) return STATUS_INVALID_IMAGE_FORMAT;
1668         if (info.wm->ldr.LoadCount != -1) info.wm->ldr.LoadCount++;
1669     }
1670     else
1671     {
1672         TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_w(info.wm->ldr.FullDllName.Buffer), info.wm->ldr.BaseAddress );
1673         info.wm->ldr.LoadCount = 1;
1674         info.wm->ldr.SectionHandle = handle;
1675     }
1676
1677     *pwm = info.wm;
1678     return STATUS_SUCCESS;
1679 }
1680
1681
1682 /***********************************************************************
1683  *      find_actctx_dll
1684  *
1685  * Find the full path (if any) of the dll from the activation context.
1686  */
1687 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
1688 {
1689     static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
1690     static const WCHAR dotManifestW[] = {'.','m','a','n','i','f','e','s','t',0};
1691
1692     ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
1693     ACTCTX_SECTION_KEYED_DATA data;
1694     UNICODE_STRING nameW;
1695     NTSTATUS status;
1696     SIZE_T needed, size = 1024;
1697     WCHAR *p;
1698
1699     RtlInitUnicodeString( &nameW, libname );
1700     data.cbSize = sizeof(data);
1701     status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
1702                                                     ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
1703                                                     &nameW, &data );
1704     if (status != STATUS_SUCCESS) return status;
1705
1706     for (;;)
1707     {
1708         if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
1709         {
1710             status = STATUS_NO_MEMORY;
1711             goto done;
1712         }
1713         status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
1714                                                        AssemblyDetailedInformationInActivationContext,
1715                                                        info, size, &needed );
1716         if (status == STATUS_SUCCESS) break;
1717         if (status != STATUS_BUFFER_TOO_SMALL) goto done;
1718         RtlFreeHeap( GetProcessHeap(), 0, info );
1719         size = needed;
1720         /* restart with larger buffer */
1721     }
1722
1723     if ((p = strrchrW( info->lpAssemblyManifestPath, '\\' )))
1724     {
1725         DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
1726
1727         p++;
1728         if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
1729         {
1730             /* manifest name does not match directory name, so it's not a global
1731              * windows/winsxs manifest; use the manifest directory name instead */
1732             dirlen = p - info->lpAssemblyManifestPath;
1733             needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
1734             if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
1735             {
1736                 status = STATUS_NO_MEMORY;
1737                 goto done;
1738             }
1739             memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
1740             p += dirlen;
1741             strcpyW( p, libname );
1742             goto done;
1743         }
1744     }
1745
1746     needed = (windows_dir.Length + sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength +
1747               nameW.Length + 2*sizeof(WCHAR));
1748
1749     if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
1750     {
1751         status = STATUS_NO_MEMORY;
1752         goto done;
1753     }
1754     memcpy( p, windows_dir.Buffer, windows_dir.Length );
1755     p += windows_dir.Length / sizeof(WCHAR);
1756     memcpy( p, winsxsW, sizeof(winsxsW) );
1757     p += sizeof(winsxsW) / sizeof(WCHAR);
1758     memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
1759     p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
1760     *p++ = '\\';
1761     strcpyW( p, libname );
1762 done:
1763     RtlFreeHeap( GetProcessHeap(), 0, info );
1764     RtlReleaseActivationContext( data.hActCtx );
1765     return status;
1766 }
1767
1768
1769 /***********************************************************************
1770  *      find_dll_file
1771  *
1772  * Find the file (or already loaded module) for a given dll name.
1773  */
1774 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
1775                                WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
1776 {
1777     OBJECT_ATTRIBUTES attr;
1778     IO_STATUS_BLOCK io;
1779     UNICODE_STRING nt_name;
1780     WCHAR *file_part, *ext, *dllname;
1781     ULONG len;
1782
1783     /* first append .dll if needed */
1784
1785     dllname = NULL;
1786     if (!(ext = strrchrW( libname, '.')) || strchrW( ext, '/' ) || strchrW( ext, '\\'))
1787     {
1788         if (!(dllname = RtlAllocateHeap( GetProcessHeap(), 0,
1789                                          (strlenW(libname) * sizeof(WCHAR)) + sizeof(dllW) )))
1790             return STATUS_NO_MEMORY;
1791         strcpyW( dllname, libname );
1792         strcatW( dllname, dllW );
1793         libname = dllname;
1794     }
1795
1796     nt_name.Buffer = NULL;
1797
1798     if (!contains_path( libname ))
1799     {
1800         NTSTATUS status;
1801         WCHAR *fullname = NULL;
1802
1803         if ((*pwm = find_basename_module( libname )) != NULL) goto found;
1804
1805         status = find_actctx_dll( libname, &fullname );
1806         if (status == STATUS_SUCCESS)
1807         {
1808             TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
1809             RtlFreeHeap( GetProcessHeap(), 0, dllname );
1810             libname = dllname = fullname;
1811         }
1812         else if (status != STATUS_SXS_KEY_NOT_FOUND)
1813         {
1814             RtlFreeHeap( GetProcessHeap(), 0, dllname );
1815             return status;
1816         }
1817     }
1818
1819     if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
1820     {
1821         /* we need to search for it */
1822         len = RtlDosSearchPath_U( load_path, libname, NULL, *size, filename, &file_part );
1823         if (len)
1824         {
1825             if (len >= *size) goto overflow;
1826             if ((*pwm = find_fullname_module( filename )) || !handle) goto found;
1827
1828             if (!RtlDosPathNameToNtPathName_U( filename, &nt_name, NULL, NULL ))
1829             {
1830                 RtlFreeHeap( GetProcessHeap(), 0, dllname );
1831                 return STATUS_NO_MEMORY;
1832             }
1833             attr.Length = sizeof(attr);
1834             attr.RootDirectory = 0;
1835             attr.Attributes = OBJ_CASE_INSENSITIVE;
1836             attr.ObjectName = &nt_name;
1837             attr.SecurityDescriptor = NULL;
1838             attr.SecurityQualityOfService = NULL;
1839             if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, 0 )) *handle = 0;
1840             goto found;
1841         }
1842
1843         /* not found */
1844
1845         if (!contains_path( libname ))
1846         {
1847             /* if libname doesn't contain a path at all, we simply return the name as is,
1848              * to be loaded as builtin */
1849             len = strlenW(libname) * sizeof(WCHAR);
1850             if (len >= *size) goto overflow;
1851             strcpyW( filename, libname );
1852             goto found;
1853         }
1854     }
1855
1856     /* absolute path name, or relative path name but not found above */
1857
1858     if (!RtlDosPathNameToNtPathName_U( libname, &nt_name, &file_part, NULL ))
1859     {
1860         RtlFreeHeap( GetProcessHeap(), 0, dllname );
1861         return STATUS_NO_MEMORY;
1862     }
1863     len = nt_name.Length - 4*sizeof(WCHAR);  /* for \??\ prefix */
1864     if (len >= *size) goto overflow;
1865     memcpy( filename, nt_name.Buffer + 4, len + sizeof(WCHAR) );
1866     if (!(*pwm = find_fullname_module( filename )) && handle)
1867     {
1868         attr.Length = sizeof(attr);
1869         attr.RootDirectory = 0;
1870         attr.Attributes = OBJ_CASE_INSENSITIVE;
1871         attr.ObjectName = &nt_name;
1872         attr.SecurityDescriptor = NULL;
1873         attr.SecurityQualityOfService = NULL;
1874         if (NtOpenFile( handle, GENERIC_READ, &attr, &io, FILE_SHARE_READ|FILE_SHARE_DELETE, 0 )) *handle = 0;
1875     }
1876 found:
1877     RtlFreeUnicodeString( &nt_name );
1878     RtlFreeHeap( GetProcessHeap(), 0, dllname );
1879     return STATUS_SUCCESS;
1880
1881 overflow:
1882     RtlFreeUnicodeString( &nt_name );
1883     RtlFreeHeap( GetProcessHeap(), 0, dllname );
1884     *size = len + sizeof(WCHAR);
1885     return STATUS_BUFFER_TOO_SMALL;
1886 }
1887
1888
1889 /***********************************************************************
1890  *      load_dll  (internal)
1891  *
1892  * Load a PE style module according to the load order.
1893  * The loader_section must be locked while calling this function.
1894  */
1895 static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
1896 {
1897     enum loadorder loadorder;
1898     WCHAR buffer[32];
1899     WCHAR *filename;
1900     ULONG size;
1901     WINE_MODREF *main_exe;
1902     HANDLE handle = 0;
1903     NTSTATUS nts;
1904
1905     TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
1906
1907     *pwm = NULL;
1908     filename = buffer;
1909     size = sizeof(buffer);
1910     for (;;)
1911     {
1912         nts = find_dll_file( load_path, libname, filename, &size, pwm, &handle );
1913         if (nts == STATUS_SUCCESS) break;
1914         if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
1915         if (nts != STATUS_BUFFER_TOO_SMALL) return nts;
1916         /* grow the buffer and retry */
1917         if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
1918     }
1919
1920     if (*pwm)  /* found already loaded module */
1921     {
1922         if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
1923
1924         if (!(flags & DONT_RESOLVE_DLL_REFERENCES)) fixup_imports( *pwm, load_path );
1925
1926         TRACE("Found %s for %s at %p, count=%d\n",
1927               debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
1928               (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
1929         if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
1930         return STATUS_SUCCESS;
1931     }
1932
1933     main_exe = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
1934     loadorder = get_load_order( main_exe ? main_exe->ldr.BaseDllName.Buffer : NULL, filename );
1935
1936     if (handle && is_fake_dll( handle ))
1937     {
1938         TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) );
1939         NtClose( handle );
1940         handle = 0;
1941     }
1942
1943     switch(loadorder)
1944     {
1945     case LO_INVALID:
1946         nts = STATUS_NO_MEMORY;
1947         break;
1948     case LO_DISABLED:
1949         nts = STATUS_DLL_NOT_FOUND;
1950         break;
1951     case LO_NATIVE:
1952     case LO_NATIVE_BUILTIN:
1953         if (!handle) nts = STATUS_DLL_NOT_FOUND;
1954         else
1955         {
1956             nts = load_native_dll( load_path, filename, handle, flags, pwm );
1957             if (nts == STATUS_INVALID_FILE_FOR_SECTION)
1958                 /* not in PE format, maybe it's a builtin */
1959                 nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
1960         }
1961         if (nts == STATUS_DLL_NOT_FOUND && loadorder == LO_NATIVE_BUILTIN)
1962             nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
1963         break;
1964     case LO_BUILTIN:
1965     case LO_BUILTIN_NATIVE:
1966     case LO_DEFAULT:  /* default is builtin,native */
1967         nts = load_builtin_dll( load_path, filename, handle, flags, pwm );
1968         if (!handle) break;  /* nothing else we can try */
1969         /* file is not a builtin library, try without using the specified file */
1970         if (nts != STATUS_SUCCESS)
1971             nts = load_builtin_dll( load_path, filename, 0, flags, pwm );
1972         if (nts == STATUS_SUCCESS && loadorder == LO_DEFAULT &&
1973             (MODULE_InitDLL( *pwm, DLL_WINE_PREATTACH, NULL ) != STATUS_SUCCESS))
1974         {
1975             /* stub-only dll, try native */
1976             TRACE( "%s pre-attach returned FALSE, preferring native\n", debugstr_w(filename) );
1977             LdrUnloadDll( (*pwm)->ldr.BaseAddress );
1978             nts = STATUS_DLL_NOT_FOUND;
1979         }
1980         if (nts == STATUS_DLL_NOT_FOUND && loadorder != LO_BUILTIN)
1981             nts = load_native_dll( load_path, filename, handle, flags, pwm );
1982         break;
1983     }
1984
1985     if (nts == STATUS_SUCCESS)
1986     {
1987         /* Initialize DLL just loaded */
1988         TRACE("Loaded module %s (%s) at %p\n", debugstr_w(filename),
1989               ((*pwm)->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native",
1990               (*pwm)->ldr.BaseAddress);
1991         if (handle) NtClose( handle );
1992         if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
1993         return nts;
1994     }
1995
1996     WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
1997     if (handle) NtClose( handle );
1998     if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
1999     return nts;
2000 }
2001
2002 /******************************************************************
2003  *              LdrLoadDll (NTDLL.@)
2004  */
2005 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags,
2006                            const UNICODE_STRING *libname, HMODULE* hModule)
2007 {
2008     WINE_MODREF *wm;
2009     NTSTATUS nts;
2010
2011     RtlEnterCriticalSection( &loader_section );
2012
2013     if (!path_name) path_name = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
2014     nts = load_dll( path_name, libname->Buffer, flags, &wm );
2015
2016     if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
2017     {
2018         nts = process_attach( wm, NULL );
2019         if (nts != STATUS_SUCCESS)
2020         {
2021             LdrUnloadDll(wm->ldr.BaseAddress);
2022             wm = NULL;
2023         }
2024     }
2025     *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
2026
2027     RtlLeaveCriticalSection( &loader_section );
2028     return nts;
2029 }
2030
2031
2032 /******************************************************************
2033  *              LdrGetDllHandle (NTDLL.@)
2034  */
2035 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
2036 {
2037     NTSTATUS status;
2038     WCHAR buffer[128];
2039     WCHAR *filename;
2040     ULONG size;
2041     WINE_MODREF *wm;
2042
2043     RtlEnterCriticalSection( &loader_section );
2044
2045     if (!load_path) load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
2046
2047     filename = buffer;
2048     size = sizeof(buffer);
2049     for (;;)
2050     {
2051         status = find_dll_file( load_path, name->Buffer, filename, &size, &wm, NULL );
2052         if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
2053         if (status != STATUS_BUFFER_TOO_SMALL) break;
2054         /* grow the buffer and retry */
2055         if (!(filename = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2056         {
2057             status = STATUS_NO_MEMORY;
2058             break;
2059         }
2060     }
2061
2062     if (status == STATUS_SUCCESS)
2063     {
2064         if (wm) *base = wm->ldr.BaseAddress;
2065         else status = STATUS_DLL_NOT_FOUND;
2066     }
2067
2068     RtlLeaveCriticalSection( &loader_section );
2069     TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
2070     return status;
2071 }
2072
2073
2074 /******************************************************************
2075  *              LdrAddRefDll (NTDLL.@)
2076  */
2077 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
2078 {
2079     NTSTATUS ret = STATUS_SUCCESS;
2080     WINE_MODREF *wm;
2081
2082     if (flags) FIXME( "%p flags %x not implemented\n", module, flags );
2083
2084     RtlEnterCriticalSection( &loader_section );
2085
2086     if ((wm = get_modref( module )))
2087     {
2088         if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2089         TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
2090     }
2091     else ret = STATUS_INVALID_PARAMETER;
2092
2093     RtlLeaveCriticalSection( &loader_section );
2094     return ret;
2095 }
2096
2097
2098 /***********************************************************************
2099  *           LdrProcessRelocationBlock  (NTDLL.@)
2100  *
2101  * Apply relocations to a given page of a mapped PE image.
2102  */
2103 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
2104                                                           USHORT *relocs, INT_PTR delta )
2105 {
2106     while (count--)
2107     {
2108         USHORT offset = *relocs & 0xfff;
2109         int type = *relocs >> 12;
2110         switch(type)
2111         {
2112         case IMAGE_REL_BASED_ABSOLUTE:
2113             break;
2114 #ifdef __i386__
2115         case IMAGE_REL_BASED_HIGH:
2116             *(short *)((char *)page + offset) += HIWORD(delta);
2117             break;
2118         case IMAGE_REL_BASED_LOW:
2119             *(short *)((char *)page + offset) += LOWORD(delta);
2120             break;
2121         case IMAGE_REL_BASED_HIGHLOW:
2122             *(int *)((char *)page + offset) += delta;
2123             break;
2124 #elif defined(__x86_64__)
2125         case IMAGE_REL_BASED_DIR64:
2126             *(INT_PTR *)((char *)page + offset) += delta;
2127             break;
2128 #endif
2129         default:
2130             FIXME("Unknown/unsupported fixup type %x.\n", type);
2131             return NULL;
2132         }
2133         relocs++;
2134     }
2135     return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
2136 }
2137
2138
2139 /******************************************************************
2140  *              LdrQueryProcessModuleInformation
2141  *
2142  */
2143 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi, 
2144                                                  ULONG buf_size, ULONG* req_size)
2145 {
2146     SYSTEM_MODULE*      sm = &smi->Modules[0];
2147     ULONG               size = sizeof(ULONG);
2148     NTSTATUS            nts = STATUS_SUCCESS;
2149     ANSI_STRING         str;
2150     char*               ptr;
2151     PLIST_ENTRY         mark, entry;
2152     PLDR_MODULE         mod;
2153     WORD id = 0;
2154
2155     smi->ModulesCount = 0;
2156
2157     RtlEnterCriticalSection( &loader_section );
2158     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2159     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2160     {
2161         mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
2162         size += sizeof(*sm);
2163         if (size <= buf_size)
2164         {
2165             sm->Reserved1 = 0; /* FIXME */
2166             sm->Reserved2 = 0; /* FIXME */
2167             sm->ImageBaseAddress = mod->BaseAddress;
2168             sm->ImageSize = mod->SizeOfImage;
2169             sm->Flags = mod->Flags;
2170             sm->Id = id++;
2171             sm->Rank = 0; /* FIXME */
2172             sm->Unknown = 0; /* FIXME */
2173             str.Length = 0;
2174             str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
2175             str.Buffer = (char*)sm->Name;
2176             RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
2177             ptr = strrchr(str.Buffer, '\\');
2178             sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
2179
2180             smi->ModulesCount++;
2181             sm++;
2182         }
2183         else nts = STATUS_INFO_LENGTH_MISMATCH;
2184     }
2185     RtlLeaveCriticalSection( &loader_section );
2186
2187     if (req_size) *req_size = size;
2188
2189     return nts;
2190 }
2191
2192
2193 /******************************************************************
2194  *              RtlDllShutdownInProgress  (NTDLL.@)
2195  */
2196 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
2197 {
2198     return process_detaching;
2199 }
2200
2201
2202 /******************************************************************
2203  *              LdrShutdownProcess (NTDLL.@)
2204  *
2205  */
2206 void WINAPI LdrShutdownProcess(void)
2207 {
2208     TRACE("()\n");
2209     process_detach( TRUE, (LPVOID)1 );
2210 }
2211
2212 /******************************************************************
2213  *              LdrShutdownThread (NTDLL.@)
2214  *
2215  */
2216 void WINAPI LdrShutdownThread(void)
2217 {
2218     PLIST_ENTRY mark, entry;
2219     PLDR_MODULE mod;
2220
2221     TRACE("()\n");
2222
2223     /* don't do any detach calls if process is exiting */
2224     if (process_detaching) return;
2225     /* FIXME: there is still a race here */
2226
2227     RtlEnterCriticalSection( &loader_section );
2228
2229     mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
2230     for (entry = mark->Blink; entry != mark; entry = entry->Blink)
2231     {
2232         mod = CONTAINING_RECORD(entry, LDR_MODULE, 
2233                                 InInitializationOrderModuleList);
2234         if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
2235             continue;
2236         if ( mod->Flags & LDR_NO_DLL_CALLS )
2237             continue;
2238
2239         MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), 
2240                         DLL_THREAD_DETACH, NULL );
2241     }
2242
2243     RtlLeaveCriticalSection( &loader_section );
2244     RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->ThreadLocalStoragePointer );
2245 }
2246
2247
2248 /***********************************************************************
2249  *           free_modref
2250  *
2251  */
2252 static void free_modref( WINE_MODREF *wm )
2253 {
2254     RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
2255     RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
2256     if (wm->ldr.InInitializationOrderModuleList.Flink)
2257         RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);
2258
2259     TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
2260     if (!TRACE_ON(module))
2261         TRACE_(loaddll)("Unloaded module %s : %s\n",
2262                         debugstr_w(wm->ldr.FullDllName.Buffer),
2263                         (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
2264
2265     SERVER_START_REQ( unload_dll )
2266     {
2267         req->base = wine_server_client_ptr( wm->ldr.BaseAddress );
2268         wine_server_call( req );
2269     }
2270     SERVER_END_REQ;
2271
2272     RtlReleaseActivationContext( wm->ldr.ActivationContext );
2273     NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
2274     if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
2275     if (cached_modref == wm) cached_modref = NULL;
2276     RtlFreeUnicodeString( &wm->ldr.FullDllName );
2277     RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
2278     RtlFreeHeap( GetProcessHeap(), 0, wm );
2279 }
2280
2281 /***********************************************************************
2282  *           MODULE_FlushModrefs
2283  *
2284  * Remove all unused modrefs and call the internal unloading routines
2285  * for the library type.
2286  *
2287  * The loader_section must be locked while calling this function.
2288  */
2289 static void MODULE_FlushModrefs(void)
2290 {
2291     PLIST_ENTRY mark, entry, prev;
2292     PLDR_MODULE mod;
2293     WINE_MODREF*wm;
2294
2295     mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
2296     for (entry = mark->Blink; entry != mark; entry = prev)
2297     {
2298         mod = CONTAINING_RECORD(entry, LDR_MODULE, InInitializationOrderModuleList);
2299         wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
2300         prev = entry->Blink;
2301         if (!mod->LoadCount) free_modref( wm );
2302     }
2303
2304     /* check load order list too for modules that haven't been initialized yet */
2305     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2306     for (entry = mark->Blink; entry != mark; entry = prev)
2307     {
2308         mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
2309         wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
2310         prev = entry->Blink;
2311         if (!mod->LoadCount) free_modref( wm );
2312     }
2313 }
2314
2315 /***********************************************************************
2316  *           MODULE_DecRefCount
2317  *
2318  * The loader_section must be locked while calling this function.
2319  */
2320 static void MODULE_DecRefCount( WINE_MODREF *wm )
2321 {
2322     int i;
2323
2324     if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
2325         return;
2326
2327     if ( wm->ldr.LoadCount <= 0 )
2328         return;
2329
2330     --wm->ldr.LoadCount;
2331     TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
2332
2333     if ( wm->ldr.LoadCount == 0 )
2334     {
2335         wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
2336
2337         for ( i = 0; i < wm->nDeps; i++ )
2338             if ( wm->deps[i] )
2339                 MODULE_DecRefCount( wm->deps[i] );
2340
2341         wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
2342     }
2343 }
2344
2345 /******************************************************************
2346  *              LdrUnloadDll (NTDLL.@)
2347  *
2348  *
2349  */
2350 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
2351 {
2352     NTSTATUS retv = STATUS_SUCCESS;
2353
2354     TRACE("(%p)\n", hModule);
2355
2356     RtlEnterCriticalSection( &loader_section );
2357
2358     /* if we're stopping the whole process (and forcing the removal of all
2359      * DLLs) the library will be freed anyway
2360      */
2361     if (!process_detaching)
2362     {
2363         WINE_MODREF *wm;
2364
2365         free_lib_count++;
2366         if ((wm = get_modref( hModule )) != NULL)
2367         {
2368             TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
2369
2370             /* Recursively decrement reference counts */
2371             MODULE_DecRefCount( wm );
2372
2373             /* Call process detach notifications */
2374             if ( free_lib_count <= 1 )
2375             {
2376                 process_detach( FALSE, NULL );
2377                 MODULE_FlushModrefs();
2378             }
2379
2380             TRACE("END\n");
2381         }
2382         else
2383             retv = STATUS_DLL_NOT_FOUND;
2384
2385         free_lib_count--;
2386     }
2387
2388     RtlLeaveCriticalSection( &loader_section );
2389
2390     return retv;
2391 }
2392
2393 /***********************************************************************
2394  *           RtlImageNtHeader   (NTDLL.@)
2395  */
2396 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
2397 {
2398     IMAGE_NT_HEADERS *ret;
2399
2400     __TRY
2401     {
2402         IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
2403
2404         ret = NULL;
2405         if (dos->e_magic == IMAGE_DOS_SIGNATURE)
2406         {
2407             ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
2408             if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
2409         }
2410     }
2411     __EXCEPT_PAGE_FAULT
2412     {
2413         return NULL;
2414     }
2415     __ENDTRY
2416     return ret;
2417 }
2418
2419
2420 /***********************************************************************
2421  *           attach_process_dlls
2422  *
2423  * Initial attach to all the dlls loaded by the process.
2424  */
2425 static NTSTATUS attach_process_dlls( void *wm )
2426 {
2427     NTSTATUS status;
2428
2429     pthread_functions.sigprocmask( SIG_UNBLOCK, &server_block_set, NULL );
2430
2431     RtlEnterCriticalSection( &loader_section );
2432     if ((status = process_attach( wm, (LPVOID)1 )) != STATUS_SUCCESS)
2433     {
2434         if (last_failed_modref)
2435             ERR( "%s failed to initialize, aborting\n",
2436                  debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
2437         return status;
2438     }
2439     attach_implicitly_loaded_dlls( (LPVOID)1 );
2440     RtlLeaveCriticalSection( &loader_section );
2441     return status;
2442 }
2443
2444
2445 /******************************************************************
2446  *              LdrInitializeThunk (NTDLL.@)
2447  *
2448  */
2449 void WINAPI LdrInitializeThunk( ULONG unknown1, ULONG unknown2, ULONG unknown3, ULONG unknown4 )
2450 {
2451     NTSTATUS status;
2452     WINE_MODREF *wm;
2453     LPCWSTR load_path;
2454     SIZE_T stack_size;
2455     PEB *peb = NtCurrentTeb()->Peb;
2456     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );
2457
2458     if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */
2459
2460     /* allocate the modref for the main exe (if not already done) */
2461     wm = get_modref( peb->ImageBaseAddress );
2462     assert( wm );
2463     if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
2464     {
2465         ERR("%s is a dll, not an executable\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
2466         exit(1);
2467     }
2468
2469     peb->LoaderLock = &loader_section;
2470     peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
2471     version_init( wm->ldr.FullDllName.Buffer );
2472
2473     /* the main exe needs to be the first in the load order list */
2474     RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
2475     InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
2476
2477     stack_size = max( nt->OptionalHeader.SizeOfStackReserve, nt->OptionalHeader.SizeOfStackCommit );
2478     if (stack_size < 1024 * 1024) stack_size = 1024 * 1024;  /* Xlib needs a large stack */
2479
2480     if ((status = virtual_alloc_thread_stack( NULL, stack_size )) != STATUS_SUCCESS) goto error;
2481     if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
2482
2483     actctx_init();
2484     load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
2485     if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
2486     if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
2487     if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
2488     if (nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) VIRTUAL_UseLargeAddressSpace();
2489
2490     status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
2491     if (status != STATUS_SUCCESS) goto error;
2492
2493     virtual_clear_thread_stack();
2494     return;
2495
2496 error:
2497     ERR( "Main exe initialization for %s failed, status %x\n",
2498          debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), status );
2499     NtTerminateProcess( GetCurrentProcess(), status );
2500 }
2501
2502
2503 /***********************************************************************
2504  *           RtlImageDirectoryEntryToData   (NTDLL.@)
2505  */
2506 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
2507 {
2508     const IMAGE_NT_HEADERS *nt;
2509     DWORD addr;
2510
2511     if ((ULONG_PTR)module & 1)  /* mapped as data file */
2512     {
2513         module = (HMODULE)((ULONG_PTR)module & ~1);
2514         image = FALSE;
2515     }
2516     if (!(nt = RtlImageNtHeader( module ))) return NULL;
2517     if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
2518     if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
2519     *size = nt->OptionalHeader.DataDirectory[dir].Size;
2520     if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
2521
2522     /* not mapped as image, need to find the section containing the virtual address */
2523     return RtlImageRvaToVa( nt, module, addr, NULL );
2524 }
2525
2526
2527 /***********************************************************************
2528  *           RtlImageRvaToSection   (NTDLL.@)
2529  */
2530 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
2531                                                    HMODULE module, DWORD rva )
2532 {
2533     int i;
2534     const IMAGE_SECTION_HEADER *sec;
2535
2536     sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
2537                                         nt->FileHeader.SizeOfOptionalHeader);
2538     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
2539     {
2540         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
2541             return (PIMAGE_SECTION_HEADER)sec;
2542     }
2543     return NULL;
2544 }
2545
2546
2547 /***********************************************************************
2548  *           RtlImageRvaToVa   (NTDLL.@)
2549  */
2550 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
2551                               DWORD rva, IMAGE_SECTION_HEADER **section )
2552 {
2553     IMAGE_SECTION_HEADER *sec;
2554
2555     if (section && *section)  /* try this section first */
2556     {
2557         sec = *section;
2558         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
2559             goto found;
2560     }
2561     if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
2562  found:
2563     if (section) *section = sec;
2564     return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
2565 }
2566
2567
2568 /***********************************************************************
2569  *           RtlPcToFileHeader   (NTDLL.@)
2570  */
2571 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
2572 {
2573     LDR_MODULE *module;
2574     PVOID ret = NULL;
2575
2576     RtlEnterCriticalSection( &loader_section );
2577     if (!LdrFindEntryForAddress( pc, &module )) ret = module->BaseAddress;
2578     RtlLeaveCriticalSection( &loader_section );
2579     *address = ret;
2580     return ret;
2581 }
2582
2583
2584 /***********************************************************************
2585  *           NtLoadDriver   (NTDLL.@)
2586  *           ZwLoadDriver   (NTDLL.@)
2587  */
2588 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *DriverServiceName )
2589 {
2590     FIXME("(%p), stub!\n",DriverServiceName);
2591     return STATUS_NOT_IMPLEMENTED;
2592 }
2593
2594
2595 /***********************************************************************
2596  *           NtUnloadDriver   (NTDLL.@)
2597  *           ZwUnloadDriver   (NTDLL.@)
2598  */
2599 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *DriverServiceName )
2600 {
2601     FIXME("(%p), stub!\n",DriverServiceName);
2602     return STATUS_NOT_IMPLEMENTED;
2603 }
2604
2605
2606 /******************************************************************
2607  *              DllMain   (NTDLL.@)
2608  */
2609 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
2610 {
2611     if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
2612     return TRUE;
2613 }
2614
2615
2616 /******************************************************************
2617  *              __wine_init_windows_dir   (NTDLL.@)
2618  *
2619  * Windows and system dir initialization once kernel32 has been loaded.
2620  */
2621 void CDECL __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir )
2622 {
2623     PLIST_ENTRY mark, entry;
2624     LPWSTR buffer, p;
2625
2626     RtlCreateUnicodeString( &windows_dir, windir );
2627     RtlCreateUnicodeString( &system_dir, sysdir );
2628     strcpyW( user_shared_data->NtSystemRoot, windir );
2629
2630     /* prepend the system dir to the name of the already created modules */
2631     mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
2632     for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2633     {
2634         LDR_MODULE *mod = CONTAINING_RECORD( entry, LDR_MODULE, InLoadOrderModuleList );
2635
2636         assert( mod->Flags & LDR_WINE_INTERNAL );
2637
2638         buffer = RtlAllocateHeap( GetProcessHeap(), 0,
2639                                   system_dir.Length + mod->FullDllName.Length + 2*sizeof(WCHAR) );
2640         if (!buffer) continue;
2641         strcpyW( buffer, system_dir.Buffer );
2642         p = buffer + strlenW( buffer );
2643         if (p > buffer && p[-1] != '\\') *p++ = '\\';
2644         strcpyW( p, mod->FullDllName.Buffer );
2645         RtlInitUnicodeString( &mod->FullDllName, buffer );
2646         RtlInitUnicodeString( &mod->BaseDllName, p );
2647     }
2648 }
2649
2650
2651 /***********************************************************************
2652  *           __wine_process_init
2653  */
2654 void __wine_process_init(void)
2655 {
2656     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
2657
2658     WINE_MODREF *wm;
2659     NTSTATUS status;
2660     ANSI_STRING func_name;
2661     void (* DECLSPEC_NORETURN CDECL init_func)(void);
2662     extern mode_t FILE_umask;
2663
2664     main_exe_file = thread_init();
2665
2666     /* retrieve current umask */
2667     FILE_umask = umask(0777);
2668     umask( FILE_umask );
2669
2670     /* setup the load callback and create ntdll modref */
2671     wine_dll_set_callback( load_builtin_callback );
2672
2673     if ((status = load_builtin_dll( NULL, kernel32W, 0, 0, &wm )) != STATUS_SUCCESS)
2674     {
2675         MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
2676         exit(1);
2677     }
2678     RtlInitAnsiString( &func_name, "UnhandledExceptionFilter" );
2679     LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name, 0, (void **)&unhandled_exception_filter );
2680
2681     RtlInitAnsiString( &func_name, "__wine_kernel_init" );
2682     if ((status = LdrGetProcedureAddress( wm->ldr.BaseAddress, &func_name,
2683                                           0, (void **)&init_func )) != STATUS_SUCCESS)
2684     {
2685         MESSAGE( "wine: could not find __wine_kernel_init in kernel32.dll, status %x\n", status );
2686         exit(1);
2687     }
2688     init_func();
2689 }