module.c 25.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Modules
 *
 * Copyright 1995 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <fcntl.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
26 27
#include <stdlib.h>
#include <string.h>
28
#include <sys/types.h>
29 30 31
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
32
#include "wine/winbase16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include "winerror.h"
34 35 36 37
#include "ntstatus.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
38
#include "winternl.h"
39
#include "thread.h"
40
#include "module.h"
41
#include "kernel_private.h"
42

43
#include "wine/debug.h"
44
#include "wine/unicode.h"
45
#include "wine/server.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
46

47 48
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
49

50

51
/****************************************************************************
52
 *              DisableThreadLibraryCalls (KERNEL32.@)
53
 *
Jon Griffiths's avatar
Jon Griffiths committed
54 55 56 57 58 59 60 61 62 63 64 65 66
 * Inform the module loader that thread notifications are not required for a dll.
 *
 * PARAMS
 *  hModule [I] Module handle to skip calls for
 *
 * RETURNS
 *  Success: TRUE. Thread attach and detach notifications will not be sent
 *           to hModule.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
 *
 * NOTES
 *  This is typically called from the dll entry point of a dll during process
 *  attachment, for dlls that do not need to process thread notifications.
67
 */
68
BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
69
{
70 71
    NTSTATUS    nts = LdrDisableThreadCalloutsForDll( hModule );
    if (nts == STATUS_SUCCESS) return TRUE;
72

73 74
    SetLastError( RtlNtStatusToDosError( nts ) );
    return FALSE;
75 76
}

Alexandre Julliard's avatar
Alexandre Julliard committed
77

78 79 80 81 82 83
/* Check whether a file is an OS/2 or a very old Windows executable
 * by testing on import of KERNEL.
 *
 * FIXME: is reading the module imports the only way of discerning
 *        old Windows binaries from OS/2 ones ? At least it seems so...
 */
84 85
static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
                                                 const IMAGE_OS2_HEADER *ne)
86 87
{
    DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
88
    enum binary_type ret = BINARY_OS216;
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    LPWORD modtab = NULL;
    LPSTR nametab = NULL;
    DWORD len;
    int i;

    /* read modref table */
    if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
      || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
      || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
      || (len != ne->ne_cmod*sizeof(WORD)) )
	goto broken;

    /* read imported names table */
    if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
      || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
      || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
      || (len != ne->ne_enttab - ne->ne_imptab) )
	goto broken;

    for (i=0; i < ne->ne_cmod; i++)
    {
	LPSTR module = &nametab[modtab[i]];
	TRACE("modref: %.*s\n", module[0], &module[1]);
	if (!(strncmp(&module[1], "KERNEL", module[0])))
	{ /* very old Windows file */
	    MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
115
            ret = BINARY_WIN16;
116 117 118 119 120 121 122 123 124 125 126
	    goto good;
	}
    }

broken:
    ERR("Hmm, an error occurred. Is this binary file broken ?\n");

good:
    HeapFree( GetProcessHeap(), 0, modtab);
    HeapFree( GetProcessHeap(), 0, nametab);
    SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
127
    return ret;
128 129
}

130 131
/***********************************************************************
 *           MODULE_GetBinaryType
132
 */
133
enum binary_type MODULE_GetBinaryType( HANDLE hfile, void **res_start, void **res_end )
134 135 136 137 138 139 140 141 142
{
    union
    {
        struct
        {
            unsigned char magic[4];
            unsigned char ignored[12];
            unsigned short type;
        } elf;
143 144 145 146 147 148 149
        struct
        {
            unsigned long magic;
            unsigned long cputype;
            unsigned long cpusubtype;
            unsigned long filetype;
        } macho;
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
        IMAGE_DOS_HEADER mz;
    } header;

    DWORD len;

    /* Seek to the start of the file and read the header information. */
    if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1)
        return BINARY_UNKNOWN;
    if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header))
        return BINARY_UNKNOWN;

    if (!memcmp( header.elf.magic, "\177ELF", 4 ))
    {
        /* FIXME: we don't bother to check byte order, architecture, etc. */
        switch(header.elf.type)
        {
        case 2: return BINARY_UNIX_EXE;
        case 3: return BINARY_UNIX_LIB;
        }
        return BINARY_UNKNOWN;
    }

172 173 174 175 176 177 178 179 180 181
    /* Mach-o File with Endian set to Big Endian  or Little Endian*/
    if (header.macho.magic == 0xfeedface || header.macho.magic == 0xecafdeef)
    {
        switch(header.macho.filetype)
        {
            case 0x8: /* MH_BUNDLE */ return BINARY_UNIX_LIB;
        }
        return BINARY_UNKNOWN;
    }

182 183 184 185
    /* Not ELF, try DOS */

    if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
    {
186 187 188 189 190 191
        union
        {
            IMAGE_OS2_HEADER os2;
            IMAGE_NT_HEADERS nt;
        } ext_header;

192 193 194 195 196 197 198 199 200
        /* We do have a DOS image so we will now try to seek into
         * the file by the amount indicated by the field
         * "Offset to extended header" and read in the
         * "magic" field information at that location.
         * This will tell us if there is more header information
         * to read or not.
         */
        if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
            return BINARY_DOS;
201
        if (!ReadFile( hfile, &ext_header, sizeof(ext_header), &len, NULL ) || len < 4)
202 203 204 205 206
            return BINARY_DOS;

        /* Reading the magic field succeeded so
         * we will try to determine what type it is.
         */
207
        if (!memcmp( &ext_header.nt.Signature, "PE\0\0", 4 ))
208
        {
209
            if (len >= sizeof(ext_header.nt.FileHeader))
210
            {
211 212 213 214 215 216
                if (len < sizeof(ext_header.nt))  /* clear remaining part of header if missing */
                    memset( (char *)&ext_header.nt + len, 0, sizeof(ext_header.nt) - len );
                if (res_start) *res_start = (void *)ext_header.nt.OptionalHeader.ImageBase;
                if (res_end) *res_end = (void *)(ext_header.nt.OptionalHeader.ImageBase +
                                                 ext_header.nt.OptionalHeader.SizeOfImage);
                if (ext_header.nt.FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
217 218
                return BINARY_PE_EXE;
            }
219
            return BINARY_DOS;
220 221
        }

222
        if (!memcmp( &ext_header.os2.ne_magic, "NE", 2 ))
223 224 225 226 227 228
        {
            /* This is a Windows executable (NE) header.  This can
             * mean either a 16-bit OS/2 or a 16-bit Windows or even a
             * DOS program (running under a DOS extender).  To decide
             * which, we'll have to read the NE header.
             */
229
            if (len >= sizeof(ext_header.os2))
230
            {
231
                switch ( ext_header.os2.ne_exetyp )
232 233 234
                {
                case 2:  return BINARY_WIN16;
                case 5:  return BINARY_DOS;
235
                default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ext_header.os2);
236 237 238
                }
            }
            /* Couldn't read header, so abort. */
239
            return BINARY_DOS;
240 241 242 243 244 245 246 247 248 249
        }

        /* Unknown extended header, but this file is nonetheless DOS-executable. */
        return BINARY_DOS;
    }

    return BINARY_UNKNOWN;
}

/***********************************************************************
250
 *             GetBinaryTypeW                     [KERNEL32.@]
251
 *
Jon Griffiths's avatar
Jon Griffiths committed
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
 * Determine whether a file is executable, and if so, what kind.
 *
 * PARAMS
 *  lpApplicationName [I] Path of the file to check
 *  lpBinaryType      [O] Destination for the binary type
 *
 * RETURNS
 *  TRUE, if the file is an executable, in which case lpBinaryType is set.
 *  FALSE, if the file is not an executable or if the function fails.
 *
 * NOTES
 *  The type of executable is a property that determines which subsytem an
 *  executable file runs under. lpBinaryType can be set to one of the following
 *  values:
 *   SCS_32BIT_BINARY: A Win32 based application
 *   SCS_DOS_BINARY: An MS-Dos based application
 *   SCS_WOW_BINARY: A Win16 based application
 *   SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
 *   SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
 *   SCS_OS216_BINARY: A 16bit OS/2 based application
 *
 *  To find the binary type, this function reads in the files header information.
 *  If extended header information is not present it will assume that the file
 *  is a DOS executable. If extended header information is present it will
 *  determine if the file is a 16 or 32 bit Windows executable by checking the
 *  flags in the header.
 *
 *  ".com" and ".pif" files are only recognized by their file name extension,
 *  as per native Windows.
Alexandre Julliard's avatar
Alexandre Julliard committed
281
 */
282
BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
283 284
{
    BOOL ret = FALSE;
285
    HANDLE hfile;
Alexandre Julliard's avatar
Alexandre Julliard committed
286

287
    TRACE("%s\n", debugstr_w(lpApplicationName) );
Alexandre Julliard's avatar
Alexandre Julliard committed
288

289 290 291 292 293 294 295
    /* Sanity check.
     */
    if ( lpApplicationName == NULL || lpBinaryType == NULL )
        return FALSE;

    /* Open the file indicated by lpApplicationName for reading.
     */
296
    hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
297
                         NULL, OPEN_EXISTING, 0, 0 );
298
    if ( hfile == INVALID_HANDLE_VALUE )
299 300 301 302
        return FALSE;

    /* Check binary type
     */
303
    switch(MODULE_GetBinaryType( hfile, NULL, NULL ))
304 305
    {
    case BINARY_UNKNOWN:
306 307 308 309 310
    {
        static const WCHAR comW[] = { '.','C','O','M',0 };
        static const WCHAR pifW[] = { '.','P','I','F',0 };
        const WCHAR *ptr;

311
        /* try to determine from file name */
312
        ptr = strrchrW( lpApplicationName, '.' );
313
        if (!ptr) break;
314
        if (!strcmpiW( ptr, comW ))
315 316 317 318
        {
            *lpBinaryType = SCS_DOS_BINARY;
            ret = TRUE;
        }
319
        else if (!strcmpiW( ptr, pifW ))
320 321 322 323 324
        {
            *lpBinaryType = SCS_PIF_BINARY;
            ret = TRUE;
        }
        break;
325
    }
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
    case BINARY_PE_EXE:
    case BINARY_PE_DLL:
        *lpBinaryType = SCS_32BIT_BINARY;
        ret = TRUE;
        break;
    case BINARY_WIN16:
        *lpBinaryType = SCS_WOW_BINARY;
        ret = TRUE;
        break;
    case BINARY_OS216:
        *lpBinaryType = SCS_OS216_BINARY;
        ret = TRUE;
        break;
    case BINARY_DOS:
        *lpBinaryType = SCS_DOS_BINARY;
        ret = TRUE;
        break;
    case BINARY_UNIX_EXE:
    case BINARY_UNIX_LIB:
        ret = FALSE;
        break;
    }
348 349 350

    CloseHandle( hfile );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352
}

353
/***********************************************************************
354 355
 *             GetBinaryTypeA                     [KERNEL32.@]
 *             GetBinaryType                      [KERNEL32.@]
356
 */
357
BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
358
{
359 360
    ANSI_STRING app_nameA;
    NTSTATUS status;
361

362
    TRACE("%s\n", debugstr_a(lpApplicationName));
363 364 365 366 367 368

    /* Sanity check.
     */
    if ( lpApplicationName == NULL || lpBinaryType == NULL )
        return FALSE;

369 370 371 372 373
    RtlInitAnsiString(&app_nameA, lpApplicationName);
    status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString,
                                          &app_nameA, FALSE);
    if (!status)
        return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
374

375 376
    SetLastError(RtlNtStatusToDosError(status));
    return FALSE;
377
}
Alexandre Julliard's avatar
Alexandre Julliard committed
378

Alexandre Julliard's avatar
Alexandre Julliard committed
379

Alexandre Julliard's avatar
Alexandre Julliard committed
380
/***********************************************************************
381
 *              GetModuleHandleA         (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
382
 *              GetModuleHandle32        (KERNEL.488)
Jon Griffiths's avatar
Jon Griffiths committed
383 384 385 386 387 388 389 390 391
 *
 * Get the handle of a dll loaded into the process address space.
 *
 * PARAMS
 *  module [I] Name of the dll
 *
 * RETURNS
 *  Success: A handle to the loaded dll.
 *  Failure: A NULL handle. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
392
 */
393
HMODULE WINAPI GetModuleHandleA(LPCSTR module)
Alexandre Julliard's avatar
Alexandre Julliard committed
394
{
395
    WCHAR *moduleW;
396

397
    if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
398 399
    if (!(moduleW = FILE_name_AtoW( module, FALSE ))) return 0;
    return GetModuleHandleW( moduleW );
Alexandre Julliard's avatar
Alexandre Julliard committed
400 401
}

402
/***********************************************************************
403
 *		GetModuleHandleW (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
404 405
 *
 * Unicode version of GetModuleHandleA.
406
 */
407
HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
Alexandre Julliard's avatar
Alexandre Julliard committed
408
{
409 410
    NTSTATUS            nts;
    HMODULE             ret;
411
    UNICODE_STRING      wstr;
412

413
    if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
414

415 416
    RtlInitUnicodeString( &wstr, module );
    nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
417 418 419 420 421 422
    if (nts != STATUS_SUCCESS)
    {
        SetLastError( RtlNtStatusToDosError( nts ) );
        ret = 0;
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
423 424
}

Alexandre Julliard's avatar
Alexandre Julliard committed
425

Alexandre Julliard's avatar
Alexandre Julliard committed
426
/***********************************************************************
427
 *              GetModuleFileNameA      (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
428
 *              GetModuleFileName32     (KERNEL.487)
429
 *
Jon Griffiths's avatar
Jon Griffiths committed
430 431 432 433 434 435 436 437 438 439
 * Get the file name of a loaded module from its handle.
 *
 * RETURNS
 *  Success: The length of the file name, excluding the terminating NUL.
 *  Failure: 0. Use GetLastError() to determine the cause.
 *
 * NOTES
 *  This function always returns the long path of hModule (as opposed to
 *  GetModuleFileName16() which returns short paths when the modules version
 *  field is < 4.0).
440 441
 *  The function doesn't write a terminating '\0' is the buffer is too 
 *  small.
Alexandre Julliard's avatar
Alexandre Julliard committed
442
 */
443
DWORD WINAPI GetModuleFileNameA(
Jon Griffiths's avatar
Jon Griffiths committed
444 445 446
	HMODULE hModule,	/* [in] Module handle (32 bit) */
	LPSTR lpFileName,	/* [out] Destination for file name */
        DWORD size )		/* [in] Size of lpFileName in characters */
447
{
448
    LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
449
    DWORD len;
Alexandre Julliard's avatar
Alexandre Julliard committed
450

451
    if (!filenameW)
452
    {
453 454
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
        return 0;
455
    }
456 457 458 459 460
    if ((len = GetModuleFileNameW( hModule, filenameW, size )))
    {
    	len = FILE_name_WtoA( filenameW, len, lpFileName, size );
        if (len < size) lpFileName[len] = '\0';
    }
461
    HeapFree( GetProcessHeap(), 0, filenameW );
462
    return len;
463 464
}

Alexandre Julliard's avatar
Alexandre Julliard committed
465
/***********************************************************************
466
 *              GetModuleFileNameW      (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
467 468
 *
 * Unicode version of GetModuleFileNameA.
Alexandre Julliard's avatar
Alexandre Julliard committed
469
 */
470
DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
471
{
472
    ULONG magic, len = 0;
473 474 475
    LDR_MODULE *pldr;
    NTSTATUS nts;
    WIN16_SUBSYSTEM_TIB *win16_tib;
476

477
    if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name)
478
    {
479 480 481
        len = min(size, win16_tib->exe_name->Length / sizeof(WCHAR));
        memcpy( lpFileName, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) );
        if (len < size) lpFileName[len] = '\0';
482
        goto done;
483 484
    }

485
    LdrLockLoaderLock( 0, NULL, &magic );
486

487 488
    if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
    nts = LdrFindEntryForAddress( hModule, &pldr );
489 490 491 492 493 494
    if (nts == STATUS_SUCCESS)
    {
        len = min(size, pldr->FullDllName.Length / sizeof(WCHAR));
        memcpy(lpFileName, pldr->FullDllName.Buffer, len * sizeof(WCHAR));
        if (len < size) lpFileName[len] = '\0';
    }
495
    else SetLastError( RtlNtStatusToDosError( nts ) );
496

497 498
    LdrUnlockLoaderLock( 0, magic );
done:
499 500
    TRACE( "%s\n", debugstr_wn(lpFileName, len) );
    return len;
Alexandre Julliard's avatar
Alexandre Julliard committed
501 502
}

503 504 505 506 507 508

/***********************************************************************
 *           get_dll_system_path
 */
static const WCHAR *get_dll_system_path(void)
{
509
    static WCHAR *cached_path;
510

511
    if (!cached_path)
512
    {
513
        WCHAR *p, *path;
514 515 516 517
        int len = 3;

        len += GetSystemDirectoryW( NULL, 0 );
        len += GetWindowsDirectoryW( NULL, 0 );
518
        p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
519 520 521 522 523 524
        *p++ = '.';
        *p++ = ';';
        GetSystemDirectoryW( p, path + len - p);
        p += strlenW(p);
        *p++ = ';';
        GetWindowsDirectoryW( p, path + len - p);
525
        cached_path = path;
526
    }
527
    return cached_path;
528 529 530 531
}


/******************************************************************
532
 *		MODULE_get_dll_load_path
533 534 535 536
 *
 * Compute the load path to use for a given dll.
 * Returned pointer must be freed by caller.
 */
537
WCHAR *MODULE_get_dll_load_path( LPCWSTR module )
538 539 540 541 542 543 544 545 546 547 548
{
    static const WCHAR pathW[] = {'P','A','T','H',0};

    const WCHAR *system_path = get_dll_system_path();
    const WCHAR *mod_end = NULL;
    UNICODE_STRING name, value;
    WCHAR *p, *ret;
    int len = 0, path_len = 0;

    /* adjust length for module name */

549
    if (!module) module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
550 551 552 553 554 555 556
    if (module)
    {
        mod_end = module;
        if ((p = strrchrW( mod_end, '\\' ))) mod_end = p;
        if ((p = strrchrW( mod_end, '/' ))) mod_end = p;
        if (mod_end == module + 2 && module[1] == ':') mod_end++;
        if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
557
        len += (mod_end - module) + 1;
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
    }
    len += strlenW( system_path ) + 2;

    /* get the PATH variable */

    RtlInitUnicodeString( &name, pathW );
    value.Length = 0;
    value.MaximumLength = 0;
    value.Buffer = NULL;
    if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
        path_len = value.Length;

    if (!(ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) ))) return NULL;
    p = ret;
    if (module)
    {
        memcpy( ret, module, (mod_end - module) * sizeof(WCHAR) );
        p += (mod_end - module);
576
        *p++ = ';';
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    }
    strcpyW( p, system_path );
    p += strlenW(p);
    *p++ = ';';
    value.Buffer = p;
    value.MaximumLength = path_len;

    while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
    {
        WCHAR *new_ptr;

        /* grow the buffer and retry */
        path_len = value.Length;
        if (!(new_ptr = HeapReAlloc( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
        {
            HeapFree( GetProcessHeap(), 0, ret );
            return NULL;
        }
        value.Buffer = new_ptr + (value.Buffer - ret);
        value.MaximumLength = path_len;
        ret = new_ptr;
    }
    value.Buffer[value.Length / sizeof(WCHAR)] = 0;
    return ret;
}


604 605
/******************************************************************
 *		load_library_as_datafile
606
 */
607
static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
608
{
609 610 611
    static const WCHAR dotDLL[] = {'.','d','l','l',0};

    WCHAR filenameW[MAX_PATH];
612 613
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE mapping;
614
    HMODULE module;
615

616
    *hmod = 0;
617

618 619
    if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
                     filenameW, NULL ))
620
    {
621 622
        hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
                             NULL, OPEN_EXISTING, 0, 0 );
623 624
    }
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
625 626

    mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
627
    CloseHandle( hFile );
628 629 630 631 632
    if (!mapping) return FALSE;

    module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
    CloseHandle( mapping );
    if (!module) return FALSE;
633

634 635 636 637 638 639 640 641
    /* make sure it's a valid PE file */
    if (!RtlImageNtHeader(module))
    {
        UnmapViewOfFile( module );
        return FALSE;
    }
    *hmod = (HMODULE)((char *)module + 1);  /* set low bit of handle to indicate datafile module */
    return TRUE;
642 643
}

644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665

/******************************************************************
 *		load_library
 *
 * Helper for LoadLibraryExA/W.
 */
static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
{
    NTSTATUS nts;
    HMODULE hModule;
    WCHAR *load_path;

    if (flags & LOAD_LIBRARY_AS_DATAFILE)
    {
        /* The method in load_library_as_datafile allows searching for the
         * 'native' libraries only
         */
        if (load_library_as_datafile( libname->Buffer, &hModule )) return hModule;
        flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
        /* Fallback to normal behaviour */
    }

666
    load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL );
667 668 669 670 671 672 673 674 675 676 677
    nts = LdrLoadDll( load_path, flags, libname, &hModule );
    HeapFree( GetProcessHeap(), 0, load_path );
    if (nts != STATUS_SUCCESS)
    {
        hModule = 0;
        SetLastError( RtlNtStatusToDosError( nts ) );
    }
    return hModule;
}


678 679
/******************************************************************
 *		LoadLibraryExA          (KERNEL32.@)
680
 *
Jon Griffiths's avatar
Jon Griffiths committed
681 682 683 684 685 686 687 688 689 690 691 692
 * Load a dll file into the process address space.
 *
 * PARAMS
 *  libname [I] Name of the file to load
 *  hfile   [I] Reserved, must be 0.
 *  flags   [I] Flags for loading the dll
 *
 * RETURNS
 *  Success: A handle to the loaded dll.
 *  Failure: A NULL handle. Use GetLastError() to determine the cause.
 *
 * NOTES
693 694 695
 * The HFILE parameter is not used and marked reserved in the SDK. I can
 * only guess that it should force a file to be mapped, but I rather
 * ignore the parameter because it would be extremely difficult to
696
 * integrate this with different types of module representations.
697
 */
698
HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
699
{
700
    WCHAR *libnameW;
701

702 703
    if (!(libnameW = FILE_name_AtoW( libname, FALSE ))) return 0;
    return LoadLibraryExW( libnameW, hfile, flags );
704
}
705

706 707
/***********************************************************************
 *           LoadLibraryExW       (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
708 709
 *
 * Unicode version of LoadLibraryExA.
710 711 712 713
 */
HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
{
    UNICODE_STRING      wstr;
714

715 716 717 718 719 720
    if (!libnameW)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    RtlInitUnicodeString( &wstr, libnameW );
721
    return load_library( &wstr, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
722 723 724
}

/***********************************************************************
725
 *           LoadLibraryA         (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
726 727 728 729 730 731 732 733 734 735 736 737
 *
 * Load a dll file into the process address space.
 *
 * PARAMS
 *  libname [I] Name of the file to load
 *
 * RETURNS
 *  Success: A handle to the loaded dll.
 *  Failure: A NULL handle. Use GetLastError() to determine the cause.
 *
 * NOTES
 * See LoadLibraryExA().
Alexandre Julliard's avatar
Alexandre Julliard committed
738
 */
739 740 741
HMODULE WINAPI LoadLibraryA(LPCSTR libname)
{
    return LoadLibraryExA(libname, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
742 743 744
}

/***********************************************************************
745
 *           LoadLibraryW         (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
746 747
 *
 * Unicode version of LoadLibraryA.
Alexandre Julliard's avatar
Alexandre Julliard committed
748
 */
749
HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
Alexandre Julliard's avatar
Alexandre Julliard committed
750
{
751
    return LoadLibraryExW(libnameW, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
752 753
}

754
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
755 756
 *           FreeLibrary   (KERNEL32.@)
 *           FreeLibrary32 (KERNEL.486)
Jon Griffiths's avatar
Jon Griffiths committed
757 758 759 760 761 762 763 764 765
 *
 * Free a dll loaded into the process address space.
 *
 * PARAMS
 *  hLibModule [I] Handle to the dll returned by LoadLibraryA().
 *
 * RETURNS
 *  Success: TRUE. The dll is removed if it is not still in use.
 *  Failure: FALSE. Use GetLastError() to determine the cause.
766 767 768
 */
BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
{
769 770
    BOOL                retv = FALSE;
    NTSTATUS            nts;
771

772 773 774 775 776 777
    if (!hLibModule)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

778 779 780 781 782 783 784
    if ((ULONG_PTR)hLibModule & 1)
    {
        /* this is a LOAD_LIBRARY_AS_DATAFILE module */
        char *ptr = (char *)hLibModule - 1;
        UnmapViewOfFile( ptr );
        return TRUE;
    }
785

786 787
    if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
    else SetLastError( RtlNtStatusToDosError( nts ) );
788

789 790
    return retv;
}
791

Alexandre Julliard's avatar
Alexandre Julliard committed
792
/***********************************************************************
793
 *           GetProcAddress   		(KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
794 795 796 797 798 799 800 801 802 803
 *
 * Find the address of an exported symbol in a loaded dll.
 *
 * PARAMS
 *  hModule  [I] Handle to the dll returned by LoadLibraryA().
 *  function [I] Name of the symbol, or an integer ordinal number < 16384
 *
 * RETURNS
 *  Success: A pointer to the symbol in the process address space.
 *  Failure: NULL. Use GetLastError() to determine the cause.
Alexandre Julliard's avatar
Alexandre Julliard committed
804
 */
805
FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
Alexandre Julliard's avatar
Alexandre Julliard committed
806
{
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
    NTSTATUS    nts;
    FARPROC     fp;

    if (HIWORD(function))
    {
        ANSI_STRING     str;

        RtlInitAnsiString( &str, function );
        nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
    }
    else
        nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
    if (nts != STATUS_SUCCESS)
    {
        SetLastError( RtlNtStatusToDosError( nts ) );
        fp = NULL;
    }
    return fp;
Alexandre Julliard's avatar
Alexandre Julliard committed
825 826
}

827
/***********************************************************************
828
 *           GetProcAddress32   		(KERNEL.453)
Jon Griffiths's avatar
Jon Griffiths committed
829 830 831 832 833 834 835 836 837 838
 *
 * Find the address of an exported symbol in a loaded dll.
 *
 * PARAMS
 *  hModule  [I] Handle to the dll returned by LoadLibraryA().
 *  function [I] Name of the symbol, or an integer ordinal number < 16384
 *
 * RETURNS
 *  Success: A pointer to the symbol in the process address space.
 *  Failure: NULL. Use GetLastError() to determine the cause.
839
 */
840
FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
841
{
842 843
    /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
    return GetProcAddress( hModule, function );
844
}