module.c 32.7 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 <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
#include <fcntl.h>
#include <stdlib.h>
27
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28 29
#include <string.h>
#include <sys/types.h>
30 31 32
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
33
#include "wine/winbase16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include "winerror.h"
35
#include "winternl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36
#include "heap.h"
37
#include "file.h"
38
#include "module.h"
39

40
#include "wine/debug.h"
41
#include "wine/unicode.h"
42
#include "wine/server.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
43

44 45 46
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(win32);
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
47

48 49
inline static HMODULE get_exe_module(void)
{
50 51
    HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
    return pdb[0x08 / sizeof(HANDLE)];  /* get dword at offset 0x08 in pdb */
52 53
}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
/***********************************************************************
 *           wait_input_idle
 *
 * Wrapper to call WaitForInputIdle USER function
 */
typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );

static DWORD wait_input_idle( HANDLE process, DWORD timeout )
{
    HMODULE mod = GetModuleHandleA( "user32.dll" );
    if (mod)
    {
        WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
        if (ptr) return ptr( process, timeout );
    }
    return 0;
}


73
/****************************************************************************
74
 *              DisableThreadLibraryCalls (KERNEL32.@)
75 76
 *
 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
77
 */
78
BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
79
{
80 81
    NTSTATUS    nts = LdrDisableThreadCalloutsForDll( hModule );
    if (nts == STATUS_SUCCESS) return TRUE;
82

83 84
    SetLastError( RtlNtStatusToDosError( nts ) );
    return FALSE;
85 86
}

Alexandre Julliard's avatar
Alexandre Julliard committed
87

Alexandre Julliard's avatar
Alexandre Julliard committed
88 89 90 91 92
/***********************************************************************
 *           MODULE_CreateDummyModule
 *
 * Create a dummy NE module for Win32 or Winelib.
 */
93
HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 )
Alexandre Julliard's avatar
Alexandre Julliard committed
94
{
95
    HMODULE16 hModule;
Alexandre Julliard's avatar
Alexandre Julliard committed
96 97
    NE_MODULE *pModule;
    SEGTABLEENTRY *pSegment;
Alexandre Julliard's avatar
Alexandre Julliard committed
98
    char *pStr,*s;
99
    unsigned int len;
Alexandre Julliard's avatar
Alexandre Julliard committed
100
    const char* basename;
101 102
    OFSTRUCT *ofs;
    int of_size, size;
Alexandre Julliard's avatar
Alexandre Julliard committed
103

104 105 106 107 108 109 110 111 112 113 114
    /* Extract base filename */
    basename = strrchr(filename, '\\');
    if (!basename) basename = filename;
    else basename++;
    len = strlen(basename);
    if ((s = strchr(basename, '.'))) len = s - basename;

    /* Allocate module */
    of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
                    + strlen(filename) + 1;
    size = sizeof(NE_MODULE) +
Alexandre Julliard's avatar
Alexandre Julliard committed
115
                 /* loaded file info */
116
                 ((of_size + 3) & ~3) +
Alexandre Julliard's avatar
Alexandre Julliard committed
117 118 119
                 /* segment table: DS,CS */
                 2 * sizeof(SEGTABLEENTRY) +
                 /* name table */
120
                 len + 2 +
Alexandre Julliard's avatar
Alexandre Julliard committed
121 122 123 124
                 /* several empty tables */
                 8;

    hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
125
    if (!hModule) return (HMODULE16)11;  /* invalid exe */
Alexandre Julliard's avatar
Alexandre Julliard committed
126

127
    FarSetOwner16( hModule, hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
128 129 130
    pModule = (NE_MODULE *)GlobalLock16( hModule );

    /* Set all used entries */
Alexandre Julliard's avatar
Alexandre Julliard committed
131
    pModule->magic            = IMAGE_OS2_SIGNATURE;
Alexandre Julliard's avatar
Alexandre Julliard committed
132 133 134
    pModule->count            = 1;
    pModule->next             = 0;
    pModule->flags            = 0;
135
    pModule->dgroup           = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
136 137
    pModule->ss               = 1;
    pModule->cs               = 2;
138 139
    pModule->heap_size        = 0;
    pModule->stack_size       = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
140 141 142 143 144 145
    pModule->seg_count        = 2;
    pModule->modref_count     = 0;
    pModule->nrname_size      = 0;
    pModule->fileinfo         = sizeof(NE_MODULE);
    pModule->os_flags         = NE_OSFLAGS_WINDOWS;
    pModule->self             = hModule;
146 147 148 149 150
    pModule->module32         = module32;

    /* Set version and flags */
    if (module32)
    {
151 152 153
        IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 );
        pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
                                     (nt->OptionalHeader.MinorSubsystemVersion & 0xff);
154
        pModule->flags |= NE_FFLAGS_WIN32;
155
        if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
156 157
            pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
158 159

    /* Set loaded file information */
160 161 162 163
    ofs = (OFSTRUCT *)(pModule + 1);
    memset( ofs, 0, of_size );
    ofs->cBytes = of_size < 256 ? of_size : 255;   /* FIXME */
    strcpy( ofs->szPathName, filename );
Alexandre Julliard's avatar
Alexandre Julliard committed
164

165
    pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3));
166
    pModule->seg_table = (int)pSegment - (int)pModule;
Alexandre Julliard's avatar
Alexandre Julliard committed
167 168 169 170 171 172 173 174 175 176 177 178
    /* Data segment */
    pSegment->size    = 0;
    pSegment->flags   = NE_SEGFLAGS_DATA;
    pSegment->minsize = 0x1000;
    pSegment++;
    /* Code segment */
    pSegment->flags   = 0;
    pSegment++;

    /* Module name */
    pStr = (char *)pSegment;
    pModule->name_table = (int)pStr - (int)pModule;
179
    assert(len<256);
Alexandre Julliard's avatar
Alexandre Julliard committed
180
    *pStr = len;
181
    lstrcpynA( pStr+1, basename, len+1 );
182
    pStr += len+2;
Alexandre Julliard's avatar
Alexandre Julliard committed
183 184 185 186 187

    /* All tables zero terminated */
    pModule->res_table = pModule->import_table = pModule->entry_table =
		(int)pStr - (int)pModule;

Alexandre Julliard's avatar
Alexandre Julliard committed
188
    NE_RegisterModule( pModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
189 190 191 192
    return hModule;
}


193 194 195 196 197 198
/* 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...
 */
199 200
static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
                                                 const IMAGE_OS2_HEADER *ne)
201 202
{
    DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
203
    enum binary_type ret = BINARY_OS216;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    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");
230
            ret = BINARY_WIN16;
231 232 233 234 235 236 237 238 239 240 241
	    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 */
242
    return ret;
243 244
}

245 246
/***********************************************************************
 *           MODULE_GetBinaryType
247 248 249 250 251 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 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
 */
enum binary_type MODULE_GetBinaryType( HANDLE hfile )
{
    union
    {
        struct
        {
            unsigned char magic[4];
            unsigned char ignored[12];
            unsigned short type;
        } elf;
        IMAGE_DOS_HEADER mz;
    } header;

    char magic[4];
    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;
    }

    /* Not ELF, try DOS */

    if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
    {
        /* 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.
         */
        /* But before we do we will make sure that header
         * structure encompasses the "Offset to extended header"
         * field.
         */
        if ((header.mz.e_cparhdr << 4) < sizeof(IMAGE_DOS_HEADER))
            return BINARY_DOS;
        if (header.mz.e_crlc && (header.mz.e_lfarlc < sizeof(IMAGE_DOS_HEADER)))
            return BINARY_DOS;
        if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER))
            return BINARY_DOS;
        if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
            return BINARY_DOS;
        if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
            return BINARY_DOS;

        /* Reading the magic field succeeded so
         * we will try to determine what type it is.
         */
        if (!memcmp( magic, "PE\0\0", 4 ))
        {
312
            IMAGE_FILE_HEADER FileHeader;
313

314
            if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
315
            {
316
                if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
317 318
                return BINARY_PE_EXE;
            }
319
            return BINARY_DOS;
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
        }

        if (!memcmp( magic, "NE", 2 ))
        {
            /* 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.
             */
            IMAGE_OS2_HEADER ne;
            if (    SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
                    && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
                    && len == sizeof(ne) )
            {
                switch ( ne.ne_exetyp )
                {
                case 2:  return BINARY_WIN16;
                case 5:  return BINARY_DOS;
                default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
                }
            }
            /* Couldn't read header, so abort. */
342
            return BINARY_DOS;
343 344 345 346 347 348 349 350 351 352 353 354
        }

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

    return BINARY_UNKNOWN;
}

/***********************************************************************
 *             GetBinaryTypeA                     [KERNEL32.@]
 *             GetBinaryType                      [KERNEL32.@]
355 356 357 358 359 360 361 362 363 364 365 366
 *
 * The GetBinaryType function determines whether a file is executable
 * or not and if it is it returns what type of executable it is.
 * The type of executable is a property that determines in which
 * subsystem an executable file runs under.
 *
 * Binary types returned:
 * 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 )
367
 * SCS_OS216_BINARY: A 16bit OS/2 based application
368 369 370 371 372 373
 *
 * Returns TRUE if the file is an executable in which case
 * the value pointed by lpBinaryType is set.
 * Returns FALSE if the file is not an executable or if the function fails.
 *
 * To do so it opens the file and reads in the header information
374 375
 * if the extended header information is not present it will
 * assume that the file is a DOS executable.
376
 * If the extended header information is present it will
377
 * determine if the file is a 16 or 32 bit Windows executable
378 379 380 381
 * by check the flags in the header.
 *
 * Note that .COM and .PIF files are only recognized by their
 * file name extension; but Windows does it the same way ...
Alexandre Julliard's avatar
Alexandre Julliard committed
382
 */
383 384 385
BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
{
    BOOL ret = FALSE;
386
    HANDLE hfile;
387
    char *ptr;
Alexandre Julliard's avatar
Alexandre Julliard committed
388

389
    TRACE_(win32)("%s\n", lpApplicationName );
Alexandre Julliard's avatar
Alexandre Julliard committed
390

391 392 393 394 395 396 397
    /* Sanity check.
     */
    if ( lpApplicationName == NULL || lpBinaryType == NULL )
        return FALSE;

    /* Open the file indicated by lpApplicationName for reading.
     */
398
    hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
399
                         NULL, OPEN_EXISTING, 0, 0 );
400
    if ( hfile == INVALID_HANDLE_VALUE )
401 402 403 404
        return FALSE;

    /* Check binary type
     */
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    switch(MODULE_GetBinaryType( hfile ))
    {
    case BINARY_UNKNOWN:
        /* try to determine from file name */
        ptr = strrchr( lpApplicationName, '.' );
        if (!ptr) break;
        if (!FILE_strcasecmp( ptr, ".COM" ))
        {
            *lpBinaryType = SCS_DOS_BINARY;
            ret = TRUE;
        }
        else if (!FILE_strcasecmp( ptr, ".PIF" ))
        {
            *lpBinaryType = SCS_PIF_BINARY;
            ret = TRUE;
        }
        break;
    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;
    }
444 445 446

    CloseHandle( hfile );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
447 448
}

449
/***********************************************************************
450
 *             GetBinaryTypeW                      [KERNEL32.@]
451 452 453 454 455 456
 */
BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
{
    BOOL ret = FALSE;
    LPSTR strNew = NULL;

457
    TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478

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

    /* Convert the wide string to a ascii string.
     */
    strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );

    if ( strNew != NULL )
    {
        ret = GetBinaryTypeA( strNew, lpBinaryType );

        /* Free the allocated string.
         */
        HeapFree( GetProcessHeap(), 0, strNew );
    }

    return ret;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
479

Alexandre Julliard's avatar
Alexandre Julliard committed
480

481
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
482
 *           WinExec     (KERNEL.166)
483 484 485
 */
HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
{
486 487
    LPCSTR p, args = NULL;
    LPCSTR name_beg, name_end;
488
    LPSTR name, cmdline;
489
    int arglen;
490 491 492
    HINSTANCE16 ret;
    char buffer[MAX_PATH];

493 494 495 496 497 498 499 500 501 502 503 504
    if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */
    {
      name_beg = lpCmdLine+1;
      p = strchr ( lpCmdLine+1, '"' );
      if (p)
      {
	  name_end = p;
	  args = strchr ( p, ' ' );
      }
      else /* yes, even valid with trailing '"' missing */
	  name_end = lpCmdLine+strlen(lpCmdLine);
    }
505
    else
506
    {
507 508 509 510 511 512 513 514 515 516 517 518
      name_beg = lpCmdLine;
      args = strchr( lpCmdLine, ' ' );
      name_end = args ? args : lpCmdLine+strlen(lpCmdLine);
    }

    if ((name_beg == lpCmdLine) && (!args))
    { /* just use the original cmdline string as file name */
        name = (LPSTR)lpCmdLine;
    }
    else
    {
        if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 )))
519
            return ERROR_NOT_ENOUGH_MEMORY;
520 521 522 523 524 525 526 527
        memcpy( name, name_beg, name_end - name_beg );
        name[name_end - name_beg] = '\0';
    }

    if (args)
    {
	args++;
	arglen = strlen(args);
528
	cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen );
529 530
	cmdline[0] = (BYTE)arglen;
	strcpy( cmdline + 1, args );
531 532 533
    }
    else
    {
534
	cmdline = HeapAlloc( GetProcessHeap(), 0, 2 );
535
	cmdline[0] = cmdline[1] = 0;
536 537
    }

538
    TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]);
539

540 541 542
    if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
    {
        LOADPARAMS16 params;
543
        WORD showCmd[2];
544 545
        showCmd[0] = 2;
        showCmd[1] = nCmdShow;
546

547
        params.hEnvironment = 0;
548 549
        params.cmdLine = MapLS( cmdline );
        params.showCmd = MapLS( showCmd );
550
        params.reserved = 0;
551

552
        ret = LoadModule16( buffer, &params );
553 554
        UnMapLS( params.cmdLine );
        UnMapLS( params.showCmd );
555 556 557
    }
    else ret = GetLastError();

558
    HeapFree( GetProcessHeap(), 0, cmdline );
559 560 561 562
    if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );

    if (ret == 21)  /* 32-bit module */
    {
563 564
        DWORD count;
        ReleaseThunkLock( &count );
565
        ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) );
566
        RestoreThunkLock( count );
567 568
    }
    return ret;
569
}
Alexandre Julliard's avatar
Alexandre Julliard committed
570

571
/***********************************************************************
572
 *           WinExec   (KERNEL32.@)
573
 */
574
UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
575
{
576 577
    PROCESS_INFORMATION info;
    STARTUPINFOA startup;
578
    char *cmdline;
579
    UINT ret;
580

581 582 583 584
    memset( &startup, 0, sizeof(startup) );
    startup.cb = sizeof(startup);
    startup.dwFlags = STARTF_USESHOWWINDOW;
    startup.wShowWindow = nCmdShow;
585

586
    /* cmdline needs to be writeable for CreateProcess */
587 588
    if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
    strcpy( cmdline, lpCmdLine );
589 590

    if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
591 592 593
                        0, NULL, NULL, &startup, &info ))
    {
        /* Give 30 seconds to the app to come up */
594
        if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF)
595
            WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
596
        ret = 33;
597 598 599 600
        /* Close off the handles */
        CloseHandle( info.hThread );
        CloseHandle( info.hProcess );
    }
601
    else if ((ret = GetLastError()) >= 32)
602
    {
603 604
        FIXME("Strange error set by CreateProcess: %d\n", ret );
        ret = 11;
605
    }
606
    HeapFree( GetProcessHeap(), 0, cmdline );
607
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
608 609
}

Alexandre Julliard's avatar
Alexandre Julliard committed
610
/**********************************************************************
611
 *	    LoadModule    (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
612
 */
613
HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
Alexandre Julliard's avatar
Alexandre Julliard committed
614
{
615
    LOADPARAMS *params = (LOADPARAMS *)paramBlock;
Alexandre Julliard's avatar
Alexandre Julliard committed
616
    PROCESS_INFORMATION info;
617 618
    STARTUPINFOA startup;
    HINSTANCE hInstance;
619 620 621
    LPSTR cmdline, p;
    char filename[MAX_PATH];
    BYTE len;
Alexandre Julliard's avatar
Alexandre Julliard committed
622

623
    if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND;
Alexandre Julliard's avatar
Alexandre Julliard committed
624

625 626
    if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
        !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
627
        return (HINSTANCE)GetLastError();
628

629 630
    len = (BYTE)params->lpCmdLine[0];
    if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
631
        return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY;
632 633 634 635 636 637 638 639 640 641 642 643 644

    strcpy( cmdline, filename );
    p = cmdline + strlen(cmdline);
    *p++ = ' ';
    memcpy( p, params->lpCmdLine + 1, len );
    p[len] = 0;

    memset( &startup, 0, sizeof(startup) );
    startup.cb = sizeof(startup);
    if (params->lpCmdShow)
    {
        startup.dwFlags = STARTF_USESHOWWINDOW;
        startup.wShowWindow = params->lpCmdShow[1];
645
    }
646

647 648 649 650
    if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
                        params->lpEnvAddress, NULL, &startup, &info ))
    {
        /* Give 30 seconds to the app to come up */
651
        if (wait_input_idle( info.hProcess, 30000 ) ==  0xFFFFFFFF )
652
            WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
653
        hInstance = (HINSTANCE)33;
654 655 656 657
        /* Close off the handles */
        CloseHandle( info.hThread );
        CloseHandle( info.hProcess );
    }
658
    else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32)
659
    {
660
        FIXME("Strange error set by CreateProcess: %p\n", hInstance );
661
        hInstance = (HINSTANCE)11;
662
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
663

664
    HeapFree( GetProcessHeap(), 0, cmdline );
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666 667
    return hInstance;
}

668

Alexandre Julliard's avatar
Alexandre Julliard committed
669
/***********************************************************************
670
 *              GetModuleHandleA         (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
671
 *              GetModuleHandle32        (KERNEL.488)
Alexandre Julliard's avatar
Alexandre Julliard committed
672
 */
673
HMODULE WINAPI GetModuleHandleA(LPCSTR module)
Alexandre Julliard's avatar
Alexandre Julliard committed
674
{
675 676
    NTSTATUS            nts;
    HMODULE             ret;
677
    UNICODE_STRING      wstr;
678

679
    if (!module) return get_exe_module();
680

681 682 683
    RtlCreateUnicodeStringFromAsciiz(&wstr, module);
    nts = LdrGetDllHandle(0, 0, &wstr, &ret);
    RtlFreeUnicodeString( &wstr );
684 685 686 687 688 689
    if (nts != STATUS_SUCCESS)
    {
        ret = 0;
        SetLastError( RtlNtStatusToDosError( nts ) );
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
690 691
}

692
/***********************************************************************
693
 *		GetModuleHandleW (KERNEL32.@)
694
 */
695
HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
Alexandre Julliard's avatar
Alexandre Julliard committed
696
{
697 698
    NTSTATUS            nts;
    HMODULE             ret;
699
    UNICODE_STRING      wstr;
700

701
    if (!module) return get_exe_module();
702

703 704
    RtlInitUnicodeString( &wstr, module );
    nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
705 706 707 708 709 710
    if (nts != STATUS_SUCCESS)
    {
        SetLastError( RtlNtStatusToDosError( nts ) );
        ret = 0;
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
711 712
}

Alexandre Julliard's avatar
Alexandre Julliard committed
713

Alexandre Julliard's avatar
Alexandre Julliard committed
714
/***********************************************************************
715
 *              GetModuleFileNameA      (KERNEL32.@)
Patrik Stridvall's avatar
Patrik Stridvall committed
716
 *              GetModuleFileName32     (KERNEL.487)
717 718 719 720 721
 *
 * GetModuleFileNameA seems to *always* return the long path;
 * it's only GetModuleFileName16 that decides between short/long path
 * by checking if exe version >= 4.0.
 * (SDK docu doesn't mention this)
Alexandre Julliard's avatar
Alexandre Julliard committed
722
 */
723
DWORD WINAPI GetModuleFileNameA(
724
	HMODULE hModule,	/* [in] module handle (32bit) */
Alexandre Julliard's avatar
Alexandre Julliard committed
725
	LPSTR lpFileName,	/* [out] filenamebuffer */
726 727
        DWORD size )		/* [in] size of filenamebuffer */
{
728
    LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
Alexandre Julliard's avatar
Alexandre Julliard committed
729

730
    if (!filenameW)
731
    {
732 733
        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
        return 0;
734
    }
735 736 737 738
    GetModuleFileNameW( hModule, filenameW, size );
    WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL );
    HeapFree( GetProcessHeap(), 0, filenameW );
    return strlen( lpFileName );
739 740
}

Alexandre Julliard's avatar
Alexandre Julliard committed
741
/***********************************************************************
742
 *              GetModuleFileNameW      (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
743
 */
744
DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
Alexandre Julliard's avatar
Alexandre Julliard committed
745
{
746 747
    ULONG magic;

748 749
    lpFileName[0] = 0;

750
    LdrLockLoaderLock( 0, NULL, &magic );
751 752 753 754 755 756 757 758
    if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
    {
        /* 16-bit task - get current NE module name */
        NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
        if (pModule)
        {
            WCHAR    path[MAX_PATH];

759 760
            MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH );
            GetLongPathNameW(path, lpFileName, size);
761 762
        }
    }
763
    else
764 765 766 767
    {
        LDR_MODULE* pldr;
        NTSTATUS    nts;

768
        if (!hModule) hModule = get_exe_module();
769
        nts = LdrFindEntryForAddress( hModule, &pldr );
770
        if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size);
771 772 773
        else SetLastError( RtlNtStatusToDosError( nts ) );

    }
774
    LdrUnlockLoaderLock( 0, magic );
775

776 777
    TRACE( "%s\n", debugstr_w(lpFileName) );
    return strlenW(lpFileName);
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779
}

780 781
/******************************************************************
 *		load_library_as_datafile
782
 */
783
static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
784
{
785 786 787
    static const WCHAR dotDLL[] = {'.','d','l','l',0};

    WCHAR filenameW[MAX_PATH];
788 789
    HANDLE hFile = INVALID_HANDLE_VALUE;
    HANDLE mapping;
790

791
    *hmod = 0;
792

793 794
    if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
                     filenameW, NULL ))
795
    {
796 797
        hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
                             NULL, OPEN_EXISTING, 0, 0 );
798 799 800
    }
    if (hFile == INVALID_HANDLE_VALUE) return FALSE;
    switch (MODULE_GetBinaryType( hFile ))
801
    {
802 803
    case BINARY_PE_EXE:
    case BINARY_PE_DLL:
804
        mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
805 806
        if (mapping)
        {
807
            *hmod = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
808 809 810 811 812
            CloseHandle( mapping );
        }
        break;
    default:
        break;
813
    }
814
    CloseHandle( hFile );
815

816
    return *hmod != 0;
817 818
}

819 820
/******************************************************************
 *		LoadLibraryExA          (KERNEL32.@)
821 822 823 824
 *
 * 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
825
 * integrate this with different types of module representations.
826 827
 *
 */
828
HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
Alexandre Julliard's avatar
Alexandre Julliard committed
829
{
830 831 832
    UNICODE_STRING      wstr;
    NTSTATUS            nts;
    HMODULE             hModule;
833

834 835 836 837 838
    if (!libname)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
839
    RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
840

841 842
    if (flags & LOAD_LIBRARY_AS_DATAFILE)
    {
843 844
        /* The method in load_library_as_datafile allows searching for the
         * 'native' libraries only
845
         */
846 847 848
        if (load_library_as_datafile( wstr.Buffer, &hModule))
        {
            RtlFreeUnicodeString( &wstr );
849
            return (HMODULE)((ULONG_PTR)hModule + 1);
850
        }
851 852 853
        flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
        /* Fallback to normal behaviour */
    }
854

855 856 857 858 859 860 861
    nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
    if (nts != STATUS_SUCCESS)
    {
        hModule = 0;
        SetLastError( RtlNtStatusToDosError( nts ) );
    }
    RtlFreeUnicodeString( &wstr );
862

863 864
    return hModule;
}
865

866 867 868 869 870 871 872 873
/***********************************************************************
 *           LoadLibraryExW       (KERNEL32.@)
 */
HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
{
    UNICODE_STRING      wstr;
    NTSTATUS            nts;
    HMODULE             hModule;
874

875 876 877 878 879
    if (!libnameW)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }
880

881 882
    if (flags & LOAD_LIBRARY_AS_DATAFILE)
    {
883 884
        /* The method in load_library_as_datafile allows searching for the
         * 'native' libraries only
885
         */
886
        if (load_library_as_datafile(libnameW, &hModule))
887 888 889 890
            return (HMODULE)((ULONG_PTR)hModule + 1);
        flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
        /* Fallback to normal behaviour */
    }
891

892 893 894 895 896 897 898 899
    RtlInitUnicodeString( &wstr, libnameW );
    nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
    if (nts != STATUS_SUCCESS)
    {
        hModule = 0;
        SetLastError( RtlNtStatusToDosError( nts ) );
    }
    return hModule;
Alexandre Julliard's avatar
Alexandre Julliard committed
900 901 902
}

/***********************************************************************
903
 *           LoadLibraryA         (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
904
 */
905 906 907
HMODULE WINAPI LoadLibraryA(LPCSTR libname)
{
    return LoadLibraryExA(libname, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
908 909 910
}

/***********************************************************************
911
 *           LoadLibraryW         (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
912
 */
913
HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
Alexandre Julliard's avatar
Alexandre Julliard committed
914
{
915
    return LoadLibraryExW(libnameW, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
916 917
}

918
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
919 920
 *           LoadLibrary32        (KERNEL.452)
 *           LoadSystemLibrary32  (KERNEL.482)
921 922 923 924
 */
HMODULE WINAPI LoadLibrary32_16( LPCSTR libname )
{
    HMODULE hModule;
925
    DWORD count;
926

927
    ReleaseThunkLock( &count );
928
    hModule = LoadLibraryA( libname );
929
    RestoreThunkLock( count );
930 931 932
    return hModule;
}

933
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
934 935
 *           FreeLibrary   (KERNEL32.@)
 *           FreeLibrary32 (KERNEL.486)
936 937 938
 */
BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
{
939 940
    BOOL                retv = FALSE;
    NTSTATUS            nts;
941

942 943 944 945 946 947
    if (!hLibModule)
    {
        SetLastError( ERROR_INVALID_HANDLE );
        return FALSE;
    }

948 949 950 951 952 953 954
    if ((ULONG_PTR)hLibModule & 1)
    {
        /* this is a LOAD_LIBRARY_AS_DATAFILE module */
        char *ptr = (char *)hLibModule - 1;
        UnmapViewOfFile( ptr );
        return TRUE;
    }
955

956 957
    if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
    else SetLastError( RtlNtStatusToDosError( nts ) );
958

959 960
    return retv;
}
961

962
/***********************************************************************
963
 *           FreeLibraryAndExitThread (KERNEL32.@)
964 965 966 967 968 969
 */
VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
{
    FreeLibrary(hLibModule);
    ExitThread(dwExitCode);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
970

Alexandre Julliard's avatar
Alexandre Julliard committed
971
/***********************************************************************
972
 *           PrivateLoadLibrary       (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
973 974 975
 *
 * FIXME: rough guesswork, don't know what "Private" means
 */
976
HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname)
Alexandre Julliard's avatar
Alexandre Julliard committed
977
{
978
    return LoadLibrary16(libname);
Alexandre Julliard's avatar
Alexandre Julliard committed
979 980 981
}

/***********************************************************************
982
 *           PrivateFreeLibrary       (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
983 984 985
 *
 * FIXME: rough guesswork, don't know what "Private" means
 */
986
void WINAPI PrivateFreeLibrary(HINSTANCE16 handle)
Alexandre Julliard's avatar
Alexandre Julliard committed
987
{
988
    FreeLibrary16(handle);
Alexandre Julliard's avatar
Alexandre Julliard committed
989 990 991
}


Alexandre Julliard's avatar
Alexandre Julliard committed
992
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
993
 *           GetProcAddress16   (KERNEL32.37)
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995
 * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
 */
996
FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
997 998
{
    if (!hModule) {
999
    	WARN("hModule may not be 0!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1000 1001
	return (FARPROC16)0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1002 1003
    if (HIWORD(hModule))
    {
1004
    	WARN("hModule is Win32 handle (%p)\n", hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006
	return (FARPROC16)0;
    }
1007
    return GetProcAddress16( LOWORD(hModule), name );
Alexandre Julliard's avatar
Alexandre Julliard committed
1008 1009
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1010
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1011
 *           GetProcAddress   (KERNEL.50)
Alexandre Julliard's avatar
Alexandre Julliard committed
1012
 */
1013
FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
1014 1015
{
    WORD ordinal;
Alexandre Julliard's avatar
Alexandre Julliard committed
1016
    FARPROC16 ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1017 1018

    if (!hModule) hModule = GetCurrentTask();
Alexandre Julliard's avatar
Alexandre Julliard committed
1019
    hModule = GetExePtr( hModule );
Alexandre Julliard's avatar
Alexandre Julliard committed
1020 1021 1022

    if (HIWORD(name) != 0)
    {
1023 1024
        ordinal = NE_GetOrdinal( hModule, name );
        TRACE("%04x '%s'\n", hModule, name );
Alexandre Julliard's avatar
Alexandre Julliard committed
1025 1026 1027 1028
    }
    else
    {
        ordinal = LOWORD(name);
1029
        TRACE("%04x %04x\n", hModule, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
1030
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1031
    if (!ordinal) return (FARPROC16)0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1032

Alexandre Julliard's avatar
Alexandre Julliard committed
1033
    ret = NE_GetEntryPoint( hModule, ordinal );
Alexandre Julliard's avatar
Alexandre Julliard committed
1034

1035
    TRACE("returning %08x\n", (UINT)ret );
Alexandre Julliard's avatar
Alexandre Julliard committed
1036 1037 1038 1039 1040
    return ret;
}


/***********************************************************************
1041
 *           GetProcAddress   		(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1042
 */
1043
FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
Alexandre Julliard's avatar
Alexandre Julliard committed
1044
{
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
    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
1063 1064
}

1065
/***********************************************************************
1066
 *           GetProcAddress32   		(KERNEL.453)
1067
 */
1068
FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
1069
{
1070 1071
    /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
    return GetProcAddress( hModule, function );
1072
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1073

Alexandre Julliard's avatar
Alexandre Julliard committed
1074 1075 1076 1077
/***************************************************************************
 *              HasGPHandler                    (KERNEL.338)
 */

1078
#include "pshpack1.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
1079 1080 1081 1082 1083 1084 1085
typedef struct _GPHANDLERDEF
{
    WORD selector;
    WORD rangeStart;
    WORD rangeEnd;
    WORD handler;
} GPHANDLERDEF;
1086
#include "poppack.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
1087

1088
SEGPTR WINAPI HasGPHandler16( SEGPTR address )
Alexandre Julliard's avatar
Alexandre Julliard committed
1089 1090
{
    HMODULE16 hModule;
1091
    int gpOrdinal;
Alexandre Julliard's avatar
Alexandre Julliard committed
1092 1093
    SEGPTR gpPtr;
    GPHANDLERDEF *gpHandler;
1094

1095
    if (    (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1096 1097
         && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
         && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
         && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1099
         && (gpHandler = MapSL( gpPtr )) != NULL )
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101 1102 1103 1104 1105
    {
        while (gpHandler->selector)
        {
            if (    SELECTOROF(address) == gpHandler->selector
                 && OFFSETOF(address)   >= gpHandler->rangeStart
                 && OFFSETOF(address)   <  gpHandler->rangeEnd  )
1106
                return MAKESEGPTR( gpHandler->selector, gpHandler->handler );
Alexandre Julliard's avatar
Alexandre Julliard committed
1107 1108 1109 1110 1111 1112
            gpHandler++;
        }
    }

    return 0;
}