module.c 25.9 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
	    goto good;
	}
    }

broken:
121
    ERR("Hmm, an error occurred. Is this binary file broken?\n");
122 123 124 125 126

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
    /* Mach-o File with Endian set to Big Endian or Little Endian */
173 174 175 176 177 178 179 180 181
    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 235 236 237 238
                case 1:  return BINARY_OS216; /* OS/2 */
                case 2:  return BINARY_WIN16; /* Windows */
                case 3:  return BINARY_DOS; /* European MS-DOS 4.x */
                case 4:  return BINARY_WIN16; /* Windows 386; FIXME: is this 32bit??? */
                case 5:  return BINARY_DOS; /* BOSS, Borland Operating System Services */
                /* other types, e.g. 0 is: "unknown" */
239
                default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ext_header.os2);
240 241 242
                }
            }
            /* Couldn't read header, so abort. */
243
            return BINARY_DOS;
244 245 246 247 248 249 250 251 252 253
        }

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

    return BINARY_UNKNOWN;
}

/***********************************************************************
254
 *             GetBinaryTypeW                     [KERNEL32.@]
255
 *
Jon Griffiths's avatar
Jon Griffiths committed
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 281 282 283 284
 * 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
285
 */
286
BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
287 288
{
    BOOL ret = FALSE;
289
    HANDLE hfile;
Alexandre Julliard's avatar
Alexandre Julliard committed
290

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

293 294 295 296 297 298 299
    /* Sanity check.
     */
    if ( lpApplicationName == NULL || lpBinaryType == NULL )
        return FALSE;

    /* Open the file indicated by lpApplicationName for reading.
     */
300
    hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
301
                         NULL, OPEN_EXISTING, 0, 0 );
302
    if ( hfile == INVALID_HANDLE_VALUE )
303 304 305 306
        return FALSE;

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

315
        /* try to determine from file name */
316
        ptr = strrchrW( lpApplicationName, '.' );
317
        if (!ptr) break;
318
        if (!strcmpiW( ptr, comW ))
319 320 321 322
        {
            *lpBinaryType = SCS_DOS_BINARY;
            ret = TRUE;
        }
323
        else if (!strcmpiW( ptr, pifW ))
324 325 326 327 328
        {
            *lpBinaryType = SCS_PIF_BINARY;
            ret = TRUE;
        }
        break;
329
    }
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    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;
    }
352 353 354

    CloseHandle( hfile );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
355 356
}

357
/***********************************************************************
358 359
 *             GetBinaryTypeA                     [KERNEL32.@]
 *             GetBinaryType                      [KERNEL32.@]
360
 */
361
BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
362
{
363 364
    ANSI_STRING app_nameA;
    NTSTATUS status;
365

366
    TRACE("%s\n", debugstr_a(lpApplicationName));
367 368 369 370 371 372

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

373 374 375 376 377
    RtlInitAnsiString(&app_nameA, lpApplicationName);
    status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString,
                                          &app_nameA, FALSE);
    if (!status)
        return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
378

379 380
    SetLastError(RtlNtStatusToDosError(status));
    return FALSE;
381
}
Alexandre Julliard's avatar
Alexandre Julliard committed
382

Alexandre Julliard's avatar
Alexandre Julliard committed
383

Alexandre Julliard's avatar
Alexandre Julliard committed
384
/***********************************************************************
385
 *              GetModuleHandleA         (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
386
 *              GetModuleHandle32        (KERNEL.488)
Jon Griffiths's avatar
Jon Griffiths committed
387 388 389 390 391 392 393 394 395
 *
 * 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
396
 */
397
HMODULE WINAPI GetModuleHandleA(LPCSTR module)
Alexandre Julliard's avatar
Alexandre Julliard committed
398
{
399
    WCHAR *moduleW;
400

401
    if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
402 403
    if (!(moduleW = FILE_name_AtoW( module, FALSE ))) return 0;
    return GetModuleHandleW( moduleW );
Alexandre Julliard's avatar
Alexandre Julliard committed
404 405
}

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

417
    if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
418

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

Alexandre Julliard's avatar
Alexandre Julliard committed
429

Alexandre Julliard's avatar
Alexandre Julliard committed
430
/***********************************************************************
431
 *              GetModuleFileNameA      (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
432
 *              GetModuleFileName32     (KERNEL.487)
433
 *
Jon Griffiths's avatar
Jon Griffiths committed
434 435 436 437 438 439 440 441 442 443
 * 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).
Andreas Mohr's avatar
Andreas Mohr committed
444
 *  The function doesn't write a terminating '\0' if the buffer is too 
445
 *  small.
Alexandre Julliard's avatar
Alexandre Julliard committed
446
 */
447
DWORD WINAPI GetModuleFileNameA(
Jon Griffiths's avatar
Jon Griffiths committed
448 449 450
	HMODULE hModule,	/* [in] Module handle (32 bit) */
	LPSTR lpFileName,	/* [out] Destination for file name */
        DWORD size )		/* [in] Size of lpFileName in characters */
451
{
452
    LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
453
    DWORD len;
Alexandre Julliard's avatar
Alexandre Julliard committed
454

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

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

481
    if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name)
482
    {
483 484 485
        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';
486
        goto done;
487 488
    }

489
    LdrLockLoaderLock( 0, NULL, &magic );
490

491 492
    if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
    nts = LdrFindEntryForAddress( hModule, &pldr );
493 494 495 496 497 498
    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';
    }
499
    else SetLastError( RtlNtStatusToDosError( nts ) );
500

501 502
    LdrUnlockLoaderLock( 0, magic );
done:
503 504
    TRACE( "%s\n", debugstr_wn(lpFileName, len) );
    return len;
Alexandre Julliard's avatar
Alexandre Julliard committed
505 506
}

507 508 509 510 511 512

/***********************************************************************
 *           get_dll_system_path
 */
static const WCHAR *get_dll_system_path(void)
{
513
    static WCHAR *cached_path;
514

515
    if (!cached_path)
516
    {
517
        WCHAR *p, *path;
518 519 520 521
        int len = 3;

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


/******************************************************************
536
 *		MODULE_get_dll_load_path
537 538 539 540
 *
 * Compute the load path to use for a given dll.
 * Returned pointer must be freed by caller.
 */
541
WCHAR *MODULE_get_dll_load_path( LPCWSTR module )
542 543 544 545 546 547 548 549 550 551 552
{
    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 */

553
    if (!module) module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
554 555 556 557 558 559 560
    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;
561
        len += (mod_end - module) + 1;
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    }
    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);
580
        *p++ = ';';
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
    }
    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;
}


608 609
/******************************************************************
 *		load_library_as_datafile
610
 */
611
static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
612
{
613 614 615
    static const WCHAR dotDLL[] = {'.','d','l','l',0};

    WCHAR filenameW[MAX_PATH];
616 617
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE mapping;
618
    HMODULE module;
619

620
    *hmod = 0;
621

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

    mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
631
    CloseHandle( hFile );
632 633 634 635 636
    if (!mapping) return FALSE;

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

638 639 640 641 642 643 644 645
    /* 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;
646 647
}

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669

/******************************************************************
 *		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 */
    }

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


682 683
/******************************************************************
 *		LoadLibraryExA          (KERNEL32.@)
684
 *
Jon Griffiths's avatar
Jon Griffiths committed
685 686 687 688 689 690 691 692 693 694 695 696
 * 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
697 698 699
 * 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
700
 * integrate this with different types of module representations.
701
 */
702
HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
703
{
704
    WCHAR *libnameW;
705

706 707
    if (!(libnameW = FILE_name_AtoW( libname, FALSE ))) return 0;
    return LoadLibraryExW( libnameW, hfile, flags );
708
}
709

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

719 720 721 722 723 724
    if (!libnameW)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
    RtlInitUnicodeString( &wstr, libnameW );
725
    return load_library( &wstr, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727 728
}

/***********************************************************************
729
 *           LoadLibraryA         (KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
730 731 732 733 734 735 736 737 738 739 740 741
 *
 * 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
742
 */
743 744 745
HMODULE WINAPI LoadLibraryA(LPCSTR libname)
{
    return LoadLibraryExA(libname, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
746 747 748
}

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

758
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
759 760
 *           FreeLibrary   (KERNEL32.@)
 *           FreeLibrary32 (KERNEL.486)
Jon Griffiths's avatar
Jon Griffiths committed
761 762 763 764 765 766 767 768 769
 *
 * 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.
770 771 772
 */
BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
{
773 774
    BOOL                retv = FALSE;
    NTSTATUS            nts;
775

776 777 778 779 780 781
    if (!hLibModule)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

782 783 784 785 786 787 788
    if ((ULONG_PTR)hLibModule & 1)
    {
        /* this is a LOAD_LIBRARY_AS_DATAFILE module */
        char *ptr = (char *)hLibModule - 1;
        UnmapViewOfFile( ptr );
        return TRUE;
    }
789

790 791
    if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
    else SetLastError( RtlNtStatusToDosError( nts ) );
792

793 794
    return retv;
}
795

Alexandre Julliard's avatar
Alexandre Julliard committed
796
/***********************************************************************
797
 *           GetProcAddress   		(KERNEL32.@)
Jon Griffiths's avatar
Jon Griffiths committed
798 799 800 801 802 803 804 805 806 807
 *
 * 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
808
 */
809
FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
Alexandre Julliard's avatar
Alexandre Julliard committed
810
{
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    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
829 830
}

831
/***********************************************************************
832
 *           GetProcAddress32   		(KERNEL.453)
Jon Griffiths's avatar
Jon Griffiths committed
833 834 835 836 837 838 839 840 841 842
 *
 * 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.
843
 */
844
FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
845
{
846 847
    /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
    return GetProcAddress( hModule, function );
848
}