- added LDR_MODULE structure to WINE_MODREF and made dummy filling of
[wine/testsucceed.git] / loader / module.c
blob161ef429b8b5184236c2adc8ce40cedeca31fb55
1 /*
2 * Modules
4 * Copyright 1995 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include "wine/winbase16.h"
34 #include "winerror.h"
35 #include "winternl.h"
36 #include "heap.h"
37 #include "file.h"
38 #include "module.h"
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/server.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(module);
45 WINE_DECLARE_DEBUG_CHANNEL(win32);
46 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
48 WINE_MODREF *MODULE_modref_list = NULL;
50 WINE_MODREF *exe_modref;
51 int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
53 /***********************************************************************
54 * wait_input_idle
56 * Wrapper to call WaitForInputIdle USER function
58 typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );
60 static DWORD wait_input_idle( HANDLE process, DWORD timeout )
62 HMODULE mod = GetModuleHandleA( "user32.dll" );
63 if (mod)
65 WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
66 if (ptr) return ptr( process, timeout );
68 return 0;
72 /*************************************************************************
73 * MODULE_InitDLL
75 BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
77 BOOL retv = TRUE;
79 static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
80 "THREAD_ATTACH", "THREAD_DETACH" };
81 assert( wm );
83 /* Skip calls for modules loaded with special load flags */
85 if (wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) return TRUE;
87 TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
89 /* Call the initialization routine */
90 retv = PE_InitDLL( wm->module, type, lpReserved );
92 /* The state of the module list may have changed due to the call
93 to PE_InitDLL. We cannot assume that this module has not been
94 deleted. */
95 TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
97 return retv;
101 /*************************************************************************
102 * MODULE_DllProcessAttach
104 * Send the process attach notification to all DLLs the given module
105 * depends on (recursively). This is somewhat complicated due to the fact that
107 * - we have to respect the module dependencies, i.e. modules implicitly
108 * referenced by another module have to be initialized before the module
109 * itself can be initialized
111 * - the initialization routine of a DLL can itself call LoadLibrary,
112 * thereby introducing a whole new set of dependencies (even involving
113 * the 'old' modules) at any time during the whole process
115 * (Note that this routine can be recursively entered not only directly
116 * from itself, but also via LoadLibrary from one of the called initialization
117 * routines.)
119 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
120 * the process *detach* notifications to be sent in the correct order.
121 * This must not only take into account module dependencies, but also
122 * 'hidden' dependencies created by modules calling LoadLibrary in their
123 * attach notification routine.
125 * The strategy is rather simple: we move a WINE_MODREF to the head of the
126 * list after the attach notification has returned. This implies that the
127 * detach notifications are called in the reverse of the sequence the attach
128 * notifications *returned*.
130 BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
132 BOOL retv = TRUE;
133 int i;
135 RtlEnterCriticalSection( &loader_section );
137 if (!wm)
139 wm = exe_modref;
140 PE_InitTls();
142 assert( wm );
144 /* prevent infinite recursion in case of cyclical dependencies */
145 if ( ( wm->flags & WINE_MODREF_MARKER )
146 || ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
147 goto done;
149 TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
151 /* Tag current MODREF to prevent recursive loop */
152 wm->flags |= WINE_MODREF_MARKER;
154 /* Recursively attach all DLLs this one depends on */
155 for ( i = 0; retv && i < wm->nDeps; i++ )
156 if ( wm->deps[i] )
157 retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
159 /* Call DLL entry point */
160 if ( retv )
162 retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
163 if ( retv )
164 wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
167 /* Re-insert MODREF at head of list */
168 if ( retv && wm->prev )
170 wm->prev->next = wm->next;
171 if ( wm->next ) wm->next->prev = wm->prev;
173 wm->prev = NULL;
174 wm->next = MODULE_modref_list;
175 MODULE_modref_list = wm->next->prev = wm;
178 /* Remove recursion flag */
179 wm->flags &= ~WINE_MODREF_MARKER;
181 TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
183 done:
184 RtlLeaveCriticalSection( &loader_section );
185 return retv;
188 /*************************************************************************
189 * MODULE_DllProcessDetach
191 * Send DLL process detach notifications. See the comment about calling
192 * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
193 * is set, only DLLs with zero refcount are notified.
195 void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
197 WINE_MODREF *wm;
199 RtlEnterCriticalSection( &loader_section );
200 if (bForceDetach) process_detaching = 1;
203 for ( wm = MODULE_modref_list; wm; wm = wm->next )
205 /* Check whether to detach this DLL */
206 if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
207 continue;
208 if ( wm->refCount > 0 && !bForceDetach )
209 continue;
211 /* Call detach notification */
212 wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
213 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
215 /* Restart at head of WINE_MODREF list, as entries might have
216 been added and/or removed while performing the call ... */
217 break;
219 } while ( wm );
221 RtlLeaveCriticalSection( &loader_section );
224 /*************************************************************************
225 * MODULE_DllThreadAttach
227 * Send DLL thread attach notifications. These are sent in the
228 * reverse sequence of process detach notification.
231 void MODULE_DllThreadAttach( LPVOID lpReserved )
233 WINE_MODREF *wm;
235 /* don't do any attach calls if process is exiting */
236 if (process_detaching) return;
237 /* FIXME: there is still a race here */
239 RtlEnterCriticalSection( &loader_section );
241 PE_InitTls();
243 for ( wm = MODULE_modref_list; wm; wm = wm->next )
244 if ( !wm->next )
245 break;
247 for ( ; wm; wm = wm->prev )
249 if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
250 continue;
251 if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
252 continue;
254 MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
257 RtlLeaveCriticalSection( &loader_section );
260 /****************************************************************************
261 * DisableThreadLibraryCalls (KERNEL32.@)
263 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
265 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
267 NTSTATUS nts = LdrDisableThreadCalloutsForDll( hModule );
268 if (nts == STATUS_SUCCESS) return TRUE;
270 SetLastError( RtlNtStatusToDosError( nts ) );
271 return FALSE;
275 /***********************************************************************
276 * MODULE_CreateDummyModule
278 * Create a dummy NE module for Win32 or Winelib.
280 HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 )
282 HMODULE16 hModule;
283 NE_MODULE *pModule;
284 SEGTABLEENTRY *pSegment;
285 char *pStr,*s;
286 unsigned int len;
287 const char* basename;
288 OFSTRUCT *ofs;
289 int of_size, size;
291 /* Extract base filename */
292 basename = strrchr(filename, '\\');
293 if (!basename) basename = filename;
294 else basename++;
295 len = strlen(basename);
296 if ((s = strchr(basename, '.'))) len = s - basename;
298 /* Allocate module */
299 of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
300 + strlen(filename) + 1;
301 size = sizeof(NE_MODULE) +
302 /* loaded file info */
303 ((of_size + 3) & ~3) +
304 /* segment table: DS,CS */
305 2 * sizeof(SEGTABLEENTRY) +
306 /* name table */
307 len + 2 +
308 /* several empty tables */
311 hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
312 if (!hModule) return (HMODULE16)11; /* invalid exe */
314 FarSetOwner16( hModule, hModule );
315 pModule = (NE_MODULE *)GlobalLock16( hModule );
317 /* Set all used entries */
318 pModule->magic = IMAGE_OS2_SIGNATURE;
319 pModule->count = 1;
320 pModule->next = 0;
321 pModule->flags = 0;
322 pModule->dgroup = 0;
323 pModule->ss = 1;
324 pModule->cs = 2;
325 pModule->heap_size = 0;
326 pModule->stack_size = 0;
327 pModule->seg_count = 2;
328 pModule->modref_count = 0;
329 pModule->nrname_size = 0;
330 pModule->fileinfo = sizeof(NE_MODULE);
331 pModule->os_flags = NE_OSFLAGS_WINDOWS;
332 pModule->self = hModule;
333 pModule->module32 = module32;
335 /* Set version and flags */
336 if (module32)
338 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 );
339 pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
340 (nt->OptionalHeader.MinorSubsystemVersion & 0xff);
341 pModule->flags |= NE_FFLAGS_WIN32;
342 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
343 pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
346 /* Set loaded file information */
347 ofs = (OFSTRUCT *)(pModule + 1);
348 memset( ofs, 0, of_size );
349 ofs->cBytes = of_size < 256 ? of_size : 255; /* FIXME */
350 strcpy( ofs->szPathName, filename );
352 pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3));
353 pModule->seg_table = (int)pSegment - (int)pModule;
354 /* Data segment */
355 pSegment->size = 0;
356 pSegment->flags = NE_SEGFLAGS_DATA;
357 pSegment->minsize = 0x1000;
358 pSegment++;
359 /* Code segment */
360 pSegment->flags = 0;
361 pSegment++;
363 /* Module name */
364 pStr = (char *)pSegment;
365 pModule->name_table = (int)pStr - (int)pModule;
366 assert(len<256);
367 *pStr = len;
368 lstrcpynA( pStr+1, basename, len+1 );
369 pStr += len+2;
371 /* All tables zero terminated */
372 pModule->res_table = pModule->import_table = pModule->entry_table =
373 (int)pStr - (int)pModule;
375 NE_RegisterModule( pModule );
376 return hModule;
380 /* Check whether a file is an OS/2 or a very old Windows executable
381 * by testing on import of KERNEL.
383 * FIXME: is reading the module imports the only way of discerning
384 * old Windows binaries from OS/2 ones ? At least it seems so...
386 static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
387 const IMAGE_OS2_HEADER *ne)
389 DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
390 enum binary_type ret = BINARY_OS216;
391 LPWORD modtab = NULL;
392 LPSTR nametab = NULL;
393 DWORD len;
394 int i;
396 /* read modref table */
397 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
398 || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
399 || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
400 || (len != ne->ne_cmod*sizeof(WORD)) )
401 goto broken;
403 /* read imported names table */
404 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
405 || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
406 || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
407 || (len != ne->ne_enttab - ne->ne_imptab) )
408 goto broken;
410 for (i=0; i < ne->ne_cmod; i++)
412 LPSTR module = &nametab[modtab[i]];
413 TRACE("modref: %.*s\n", module[0], &module[1]);
414 if (!(strncmp(&module[1], "KERNEL", module[0])))
415 { /* very old Windows file */
416 MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
417 ret = BINARY_WIN16;
418 goto good;
422 broken:
423 ERR("Hmm, an error occurred. Is this binary file broken ?\n");
425 good:
426 HeapFree( GetProcessHeap(), 0, modtab);
427 HeapFree( GetProcessHeap(), 0, nametab);
428 SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
429 return ret;
432 /***********************************************************************
433 * MODULE_GetBinaryType
435 enum binary_type MODULE_GetBinaryType( HANDLE hfile )
437 union
439 struct
441 unsigned char magic[4];
442 unsigned char ignored[12];
443 unsigned short type;
444 } elf;
445 IMAGE_DOS_HEADER mz;
446 } header;
448 char magic[4];
449 DWORD len;
451 /* Seek to the start of the file and read the header information. */
452 if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1)
453 return BINARY_UNKNOWN;
454 if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header))
455 return BINARY_UNKNOWN;
457 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
459 /* FIXME: we don't bother to check byte order, architecture, etc. */
460 switch(header.elf.type)
462 case 2: return BINARY_UNIX_EXE;
463 case 3: return BINARY_UNIX_LIB;
465 return BINARY_UNKNOWN;
468 /* Not ELF, try DOS */
470 if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
472 /* We do have a DOS image so we will now try to seek into
473 * the file by the amount indicated by the field
474 * "Offset to extended header" and read in the
475 * "magic" field information at that location.
476 * This will tell us if there is more header information
477 * to read or not.
479 /* But before we do we will make sure that header
480 * structure encompasses the "Offset to extended header"
481 * field.
483 if ((header.mz.e_cparhdr << 4) < sizeof(IMAGE_DOS_HEADER))
484 return BINARY_DOS;
485 if (header.mz.e_crlc && (header.mz.e_lfarlc < sizeof(IMAGE_DOS_HEADER)))
486 return BINARY_DOS;
487 if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER))
488 return BINARY_DOS;
489 if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
490 return BINARY_DOS;
491 if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
492 return BINARY_DOS;
494 /* Reading the magic field succeeded so
495 * we will try to determine what type it is.
497 if (!memcmp( magic, "PE\0\0", 4 ))
499 IMAGE_FILE_HEADER FileHeader;
501 if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
503 if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
504 return BINARY_PE_EXE;
506 return BINARY_DOS;
509 if (!memcmp( magic, "NE", 2 ))
511 /* This is a Windows executable (NE) header. This can
512 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
513 * DOS program (running under a DOS extender). To decide
514 * which, we'll have to read the NE header.
516 IMAGE_OS2_HEADER ne;
517 if ( SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
518 && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
519 && len == sizeof(ne) )
521 switch ( ne.ne_exetyp )
523 case 2: return BINARY_WIN16;
524 case 5: return BINARY_DOS;
525 default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
528 /* Couldn't read header, so abort. */
529 return BINARY_DOS;
532 /* Unknown extended header, but this file is nonetheless DOS-executable. */
533 return BINARY_DOS;
536 return BINARY_UNKNOWN;
539 /***********************************************************************
540 * GetBinaryTypeA [KERNEL32.@]
541 * GetBinaryType [KERNEL32.@]
543 * The GetBinaryType function determines whether a file is executable
544 * or not and if it is it returns what type of executable it is.
545 * The type of executable is a property that determines in which
546 * subsystem an executable file runs under.
548 * Binary types returned:
549 * SCS_32BIT_BINARY: A Win32 based application
550 * SCS_DOS_BINARY: An MS-Dos based application
551 * SCS_WOW_BINARY: A Win16 based application
552 * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
553 * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
554 * SCS_OS216_BINARY: A 16bit OS/2 based application
556 * Returns TRUE if the file is an executable in which case
557 * the value pointed by lpBinaryType is set.
558 * Returns FALSE if the file is not an executable or if the function fails.
560 * To do so it opens the file and reads in the header information
561 * if the extended header information is not present it will
562 * assume that the file is a DOS executable.
563 * If the extended header information is present it will
564 * determine if the file is a 16 or 32 bit Windows executable
565 * by check the flags in the header.
567 * Note that .COM and .PIF files are only recognized by their
568 * file name extension; but Windows does it the same way ...
570 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
572 BOOL ret = FALSE;
573 HANDLE hfile;
574 char *ptr;
576 TRACE_(win32)("%s\n", lpApplicationName );
578 /* Sanity check.
580 if ( lpApplicationName == NULL || lpBinaryType == NULL )
581 return FALSE;
583 /* Open the file indicated by lpApplicationName for reading.
585 hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
586 NULL, OPEN_EXISTING, 0, 0 );
587 if ( hfile == INVALID_HANDLE_VALUE )
588 return FALSE;
590 /* Check binary type
592 switch(MODULE_GetBinaryType( hfile ))
594 case BINARY_UNKNOWN:
595 /* try to determine from file name */
596 ptr = strrchr( lpApplicationName, '.' );
597 if (!ptr) break;
598 if (!FILE_strcasecmp( ptr, ".COM" ))
600 *lpBinaryType = SCS_DOS_BINARY;
601 ret = TRUE;
603 else if (!FILE_strcasecmp( ptr, ".PIF" ))
605 *lpBinaryType = SCS_PIF_BINARY;
606 ret = TRUE;
608 break;
609 case BINARY_PE_EXE:
610 case BINARY_PE_DLL:
611 *lpBinaryType = SCS_32BIT_BINARY;
612 ret = TRUE;
613 break;
614 case BINARY_WIN16:
615 *lpBinaryType = SCS_WOW_BINARY;
616 ret = TRUE;
617 break;
618 case BINARY_OS216:
619 *lpBinaryType = SCS_OS216_BINARY;
620 ret = TRUE;
621 break;
622 case BINARY_DOS:
623 *lpBinaryType = SCS_DOS_BINARY;
624 ret = TRUE;
625 break;
626 case BINARY_UNIX_EXE:
627 case BINARY_UNIX_LIB:
628 ret = FALSE;
629 break;
632 CloseHandle( hfile );
633 return ret;
636 /***********************************************************************
637 * GetBinaryTypeW [KERNEL32.@]
639 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
641 BOOL ret = FALSE;
642 LPSTR strNew = NULL;
644 TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
646 /* Sanity check.
648 if ( lpApplicationName == NULL || lpBinaryType == NULL )
649 return FALSE;
651 /* Convert the wide string to a ascii string.
653 strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );
655 if ( strNew != NULL )
657 ret = GetBinaryTypeA( strNew, lpBinaryType );
659 /* Free the allocated string.
661 HeapFree( GetProcessHeap(), 0, strNew );
664 return ret;
668 /***********************************************************************
669 * WinExec (KERNEL.166)
671 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
673 LPCSTR p, args = NULL;
674 LPCSTR name_beg, name_end;
675 LPSTR name, cmdline;
676 int arglen;
677 HINSTANCE16 ret;
678 char buffer[MAX_PATH];
680 if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */
682 name_beg = lpCmdLine+1;
683 p = strchr ( lpCmdLine+1, '"' );
684 if (p)
686 name_end = p;
687 args = strchr ( p, ' ' );
689 else /* yes, even valid with trailing '"' missing */
690 name_end = lpCmdLine+strlen(lpCmdLine);
692 else
694 name_beg = lpCmdLine;
695 args = strchr( lpCmdLine, ' ' );
696 name_end = args ? args : lpCmdLine+strlen(lpCmdLine);
699 if ((name_beg == lpCmdLine) && (!args))
700 { /* just use the original cmdline string as file name */
701 name = (LPSTR)lpCmdLine;
703 else
705 if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 )))
706 return ERROR_NOT_ENOUGH_MEMORY;
707 memcpy( name, name_beg, name_end - name_beg );
708 name[name_end - name_beg] = '\0';
711 if (args)
713 args++;
714 arglen = strlen(args);
715 cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen );
716 cmdline[0] = (BYTE)arglen;
717 strcpy( cmdline + 1, args );
719 else
721 cmdline = HeapAlloc( GetProcessHeap(), 0, 2 );
722 cmdline[0] = cmdline[1] = 0;
725 TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]);
727 if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
729 LOADPARAMS16 params;
730 WORD showCmd[2];
731 showCmd[0] = 2;
732 showCmd[1] = nCmdShow;
734 params.hEnvironment = 0;
735 params.cmdLine = MapLS( cmdline );
736 params.showCmd = MapLS( showCmd );
737 params.reserved = 0;
739 ret = LoadModule16( buffer, &params );
740 UnMapLS( params.cmdLine );
741 UnMapLS( params.showCmd );
743 else ret = GetLastError();
745 HeapFree( GetProcessHeap(), 0, cmdline );
746 if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
748 if (ret == 21) /* 32-bit module */
750 DWORD count;
751 ReleaseThunkLock( &count );
752 ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) );
753 RestoreThunkLock( count );
755 return ret;
758 /***********************************************************************
759 * WinExec (KERNEL32.@)
761 UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
763 PROCESS_INFORMATION info;
764 STARTUPINFOA startup;
765 char *cmdline;
766 UINT ret;
768 memset( &startup, 0, sizeof(startup) );
769 startup.cb = sizeof(startup);
770 startup.dwFlags = STARTF_USESHOWWINDOW;
771 startup.wShowWindow = nCmdShow;
773 /* cmdline needs to be writeable for CreateProcess */
774 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
775 strcpy( cmdline, lpCmdLine );
777 if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
778 0, NULL, NULL, &startup, &info ))
780 /* Give 30 seconds to the app to come up */
781 if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF)
782 WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
783 ret = 33;
784 /* Close off the handles */
785 CloseHandle( info.hThread );
786 CloseHandle( info.hProcess );
788 else if ((ret = GetLastError()) >= 32)
790 FIXME("Strange error set by CreateProcess: %d\n", ret );
791 ret = 11;
793 HeapFree( GetProcessHeap(), 0, cmdline );
794 return ret;
797 /**********************************************************************
798 * LoadModule (KERNEL32.@)
800 HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
802 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
803 PROCESS_INFORMATION info;
804 STARTUPINFOA startup;
805 HINSTANCE hInstance;
806 LPSTR cmdline, p;
807 char filename[MAX_PATH];
808 BYTE len;
810 if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND;
812 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
813 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
814 return (HINSTANCE)GetLastError();
816 len = (BYTE)params->lpCmdLine[0];
817 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
818 return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY;
820 strcpy( cmdline, filename );
821 p = cmdline + strlen(cmdline);
822 *p++ = ' ';
823 memcpy( p, params->lpCmdLine + 1, len );
824 p[len] = 0;
826 memset( &startup, 0, sizeof(startup) );
827 startup.cb = sizeof(startup);
828 if (params->lpCmdShow)
830 startup.dwFlags = STARTF_USESHOWWINDOW;
831 startup.wShowWindow = params->lpCmdShow[1];
834 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
835 params->lpEnvAddress, NULL, &startup, &info ))
837 /* Give 30 seconds to the app to come up */
838 if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF )
839 WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
840 hInstance = (HINSTANCE)33;
841 /* Close off the handles */
842 CloseHandle( info.hThread );
843 CloseHandle( info.hProcess );
845 else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32)
847 FIXME("Strange error set by CreateProcess: %p\n", hInstance );
848 hInstance = (HINSTANCE)11;
851 HeapFree( GetProcessHeap(), 0, cmdline );
852 return hInstance;
856 /***********************************************************************
857 * GetModuleHandleA (KERNEL32.@)
858 * GetModuleHandle32 (KERNEL.488)
860 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
862 NTSTATUS nts;
863 HMODULE ret;
865 if (module)
867 UNICODE_STRING wstr;
869 RtlCreateUnicodeStringFromAsciiz(&wstr, module);
870 nts = LdrGetDllHandle(0, 0, &wstr, &ret);
871 RtlFreeUnicodeString( &wstr );
873 else
874 nts = LdrGetDllHandle(0, 0, NULL, &ret);
875 if (nts != STATUS_SUCCESS)
877 ret = 0;
878 SetLastError( RtlNtStatusToDosError( nts ) );
881 return ret;
884 /***********************************************************************
885 * GetModuleHandleW (KERNEL32.@)
887 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
889 NTSTATUS nts;
890 HMODULE ret;
892 if (module)
894 UNICODE_STRING wstr;
896 RtlInitUnicodeString( &wstr, module );
897 nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
899 else
900 nts = LdrGetDllHandle( 0, 0, NULL, &ret);
902 if (nts != STATUS_SUCCESS)
904 SetLastError( RtlNtStatusToDosError( nts ) );
905 ret = 0;
907 return ret;
911 /***********************************************************************
912 * GetModuleFileNameA (KERNEL32.@)
913 * GetModuleFileName32 (KERNEL.487)
915 * GetModuleFileNameA seems to *always* return the long path;
916 * it's only GetModuleFileName16 that decides between short/long path
917 * by checking if exe version >= 4.0.
918 * (SDK docu doesn't mention this)
920 DWORD WINAPI GetModuleFileNameA(
921 HMODULE hModule, /* [in] module handle (32bit) */
922 LPSTR lpFileName, /* [out] filenamebuffer */
923 DWORD size ) /* [in] size of filenamebuffer */
925 DWORD len = 0;
927 lpFileName[0] = 0;
929 RtlEnterCriticalSection( &loader_section );
930 if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
932 /* 16-bit task - get current NE module name */
933 NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
934 if (pModule) len = GetLongPathNameA(NE_MODULE_NAME(pModule), lpFileName, size);
936 else if (hModule || LdrGetDllHandle( 0, 0, NULL, &hModule ) == STATUS_SUCCESS)
938 LDR_MODULE* pldr;
939 NTSTATUS nts;
941 nts = LdrFindEntryForAddress( hModule, &pldr );
942 if (nts == STATUS_SUCCESS)
944 WideCharToMultiByte( CP_ACP, 0,
945 pldr->FullDllName.Buffer, pldr->FullDllName.Length,
946 lpFileName, size, NULL, NULL );
947 len = min(size, pldr->FullDllName.Length / sizeof(WCHAR));
949 else SetLastError( RtlNtStatusToDosError( nts ) );
951 RtlLeaveCriticalSection( &loader_section );
953 TRACE( "%s\n", debugstr_an(lpFileName, len) );
954 return len;
958 /***********************************************************************
959 * GetModuleFileNameW (KERNEL32.@)
961 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
963 DWORD len = 0;
965 lpFileName[0] = 0;
967 RtlEnterCriticalSection( &loader_section );
968 if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
970 /* 16-bit task - get current NE module name */
971 NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
972 if (pModule)
974 WCHAR path[MAX_PATH];
976 MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1,
977 path, MAX_PATH );
978 len = GetLongPathNameW(path, lpFileName, size);
981 else if (hModule || LdrGetDllHandle( 0, 0, NULL, &hModule ) == STATUS_SUCCESS)
983 LDR_MODULE* pldr;
984 NTSTATUS nts;
986 nts = LdrFindEntryForAddress( hModule, &pldr );
987 if (nts == STATUS_SUCCESS)
989 len = min(size, pldr->FullDllName.Length / sizeof(WCHAR));
990 strncpyW(lpFileName, pldr->FullDllName.Buffer, len);
991 if (len < size) lpFileName[len] = 0;
993 else SetLastError( RtlNtStatusToDosError( nts ) );
996 RtlLeaveCriticalSection( &loader_section );
998 TRACE( "%s\n", debugstr_wn(lpFileName, len) );
999 return len;
1002 /******************************************************************
1003 * load_library_as_datafile
1005 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
1007 static const WCHAR dotDLL[] = {'.','d','l','l',0};
1009 WCHAR filenameW[MAX_PATH];
1010 HANDLE hFile = INVALID_HANDLE_VALUE;
1011 HANDLE mapping;
1013 *hmod = 0;
1015 if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
1016 filenameW, NULL ))
1018 hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
1019 NULL, OPEN_EXISTING, 0, 0 );
1021 if (hFile == INVALID_HANDLE_VALUE) return FALSE;
1022 switch (MODULE_GetBinaryType( hFile ))
1024 case BINARY_PE_EXE:
1025 case BINARY_PE_DLL:
1026 mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
1027 if (mapping)
1029 *hmod = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
1030 CloseHandle( mapping );
1032 break;
1033 default:
1034 break;
1036 CloseHandle( hFile );
1038 return *hmod != 0;
1041 /******************************************************************
1042 * LoadLibraryExA (KERNEL32.@)
1044 * The HFILE parameter is not used and marked reserved in the SDK. I can
1045 * only guess that it should force a file to be mapped, but I rather
1046 * ignore the parameter because it would be extremely difficult to
1047 * integrate this with different types of module representations.
1050 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
1052 UNICODE_STRING wstr;
1053 NTSTATUS nts;
1054 HMODULE hModule;
1056 if (!libname)
1058 SetLastError(ERROR_INVALID_PARAMETER);
1059 return 0;
1061 RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
1063 if (flags & LOAD_LIBRARY_AS_DATAFILE)
1065 /* The method in load_library_as_datafile allows searching for the
1066 * 'native' libraries only
1068 if (load_library_as_datafile( wstr.Buffer, &hModule))
1070 RtlFreeUnicodeString( &wstr );
1071 return (HMODULE)((ULONG_PTR)hModule + 1);
1073 flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
1074 /* Fallback to normal behaviour */
1077 nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
1078 if (nts != STATUS_SUCCESS)
1080 hModule = 0;
1081 SetLastError( RtlNtStatusToDosError( nts ) );
1083 RtlFreeUnicodeString( &wstr );
1085 return hModule;
1088 /***********************************************************************
1089 * LoadLibraryExW (KERNEL32.@)
1091 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
1093 UNICODE_STRING wstr;
1094 NTSTATUS nts;
1095 HMODULE hModule;
1097 if (!libnameW)
1099 SetLastError(ERROR_INVALID_PARAMETER);
1100 return 0;
1103 if (flags & LOAD_LIBRARY_AS_DATAFILE)
1105 /* The method in load_library_as_datafile allows searching for the
1106 * 'native' libraries only
1108 if (load_library_as_datafile(libnameW, &hModule))
1109 return (HMODULE)((ULONG_PTR)hModule + 1);
1110 flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
1111 /* Fallback to normal behaviour */
1114 RtlInitUnicodeString( &wstr, libnameW );
1115 nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
1116 if (nts != STATUS_SUCCESS)
1118 hModule = 0;
1119 SetLastError( RtlNtStatusToDosError( nts ) );
1121 return hModule;
1124 /***********************************************************************
1125 * LoadLibraryA (KERNEL32.@)
1127 HMODULE WINAPI LoadLibraryA(LPCSTR libname)
1129 return LoadLibraryExA(libname, 0, 0);
1132 /***********************************************************************
1133 * LoadLibraryW (KERNEL32.@)
1135 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
1137 return LoadLibraryExW(libnameW, 0, 0);
1140 /***********************************************************************
1141 * LoadLibrary32 (KERNEL.452)
1142 * LoadSystemLibrary32 (KERNEL.482)
1144 HMODULE WINAPI LoadLibrary32_16( LPCSTR libname )
1146 HMODULE hModule;
1147 DWORD count;
1149 ReleaseThunkLock( &count );
1150 hModule = LoadLibraryA( libname );
1151 RestoreThunkLock( count );
1152 return hModule;
1155 /***********************************************************************
1156 * FreeLibrary (KERNEL32.@)
1157 * FreeLibrary32 (KERNEL.486)
1159 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
1161 BOOL retv = FALSE;
1162 NTSTATUS nts;
1164 if (!hLibModule)
1166 SetLastError( ERROR_INVALID_HANDLE );
1167 return FALSE;
1170 if ((ULONG_PTR)hLibModule & 1)
1172 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
1173 char *ptr = (char *)hLibModule - 1;
1174 UnmapViewOfFile( ptr );
1175 return TRUE;
1178 if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
1179 else SetLastError( RtlNtStatusToDosError( nts ) );
1181 return retv;
1184 /***********************************************************************
1185 * FreeLibraryAndExitThread (KERNEL32.@)
1187 VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
1189 FreeLibrary(hLibModule);
1190 ExitThread(dwExitCode);
1193 /***********************************************************************
1194 * PrivateLoadLibrary (KERNEL32.@)
1196 * FIXME: rough guesswork, don't know what "Private" means
1198 HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname)
1200 return LoadLibrary16(libname);
1203 /***********************************************************************
1204 * PrivateFreeLibrary (KERNEL32.@)
1206 * FIXME: rough guesswork, don't know what "Private" means
1208 void WINAPI PrivateFreeLibrary(HINSTANCE16 handle)
1210 FreeLibrary16(handle);
1214 /***********************************************************************
1215 * GetProcAddress16 (KERNEL32.37)
1216 * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1218 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
1220 if (!hModule) {
1221 WARN("hModule may not be 0!\n");
1222 return (FARPROC16)0;
1224 if (HIWORD(hModule))
1226 WARN("hModule is Win32 handle (%p)\n", hModule );
1227 return (FARPROC16)0;
1229 return GetProcAddress16( LOWORD(hModule), name );
1232 /***********************************************************************
1233 * GetProcAddress (KERNEL.50)
1235 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name )
1237 WORD ordinal;
1238 FARPROC16 ret;
1240 if (!hModule) hModule = GetCurrentTask();
1241 hModule = GetExePtr( hModule );
1243 if (HIWORD(name) != 0)
1245 ordinal = NE_GetOrdinal( hModule, name );
1246 TRACE("%04x '%s'\n", hModule, name );
1248 else
1250 ordinal = LOWORD(name);
1251 TRACE("%04x %04x\n", hModule, ordinal );
1253 if (!ordinal) return (FARPROC16)0;
1255 ret = NE_GetEntryPoint( hModule, ordinal );
1257 TRACE("returning %08x\n", (UINT)ret );
1258 return ret;
1262 /***********************************************************************
1263 * GetProcAddress (KERNEL32.@)
1265 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
1267 NTSTATUS nts;
1268 FARPROC fp;
1270 if (HIWORD(function))
1272 ANSI_STRING str;
1274 RtlInitAnsiString( &str, function );
1275 nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
1277 else
1278 nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
1279 if (nts != STATUS_SUCCESS)
1281 SetLastError( RtlNtStatusToDosError( nts ) );
1282 fp = NULL;
1284 return fp;
1287 /***********************************************************************
1288 * GetProcAddress32 (KERNEL.453)
1290 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
1292 /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
1293 return GetProcAddress( hModule, function );
1296 /***************************************************************************
1297 * HasGPHandler (KERNEL.338)
1300 #include "pshpack1.h"
1301 typedef struct _GPHANDLERDEF
1303 WORD selector;
1304 WORD rangeStart;
1305 WORD rangeEnd;
1306 WORD handler;
1307 } GPHANDLERDEF;
1308 #include "poppack.h"
1310 SEGPTR WINAPI HasGPHandler16( SEGPTR address )
1312 HMODULE16 hModule;
1313 int gpOrdinal;
1314 SEGPTR gpPtr;
1315 GPHANDLERDEF *gpHandler;
1317 if ( (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1318 && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
1319 && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
1320 && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1321 && (gpHandler = MapSL( gpPtr )) != NULL )
1323 while (gpHandler->selector)
1325 if ( SELECTOROF(address) == gpHandler->selector
1326 && OFFSETOF(address) >= gpHandler->rangeStart
1327 && OFFSETOF(address) < gpHandler->rangeEnd )
1328 return MAKESEGPTR( gpHandler->selector, gpHandler->handler );
1329 gpHandler++;
1333 return 0;