354 lines
11 KiB
C
354 lines
11 KiB
C
/*
|
|
* Modules
|
|
*
|
|
* Copyright 1995 Alexandre Julliard
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "ntstatus.h"
|
|
#define WIN32_NO_STATUS
|
|
#include "winerror.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winternl.h"
|
|
#include "kernel_private.h"
|
|
#include "psapi.h"
|
|
|
|
#include "wine/exception.h"
|
|
#include "wine/list.h"
|
|
#include "wine/asm.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(module);
|
|
|
|
|
|
/****************************************************************************
|
|
* GetDllDirectoryA (KERNEL32.@)
|
|
*/
|
|
DWORD WINAPI GetDllDirectoryA( DWORD buf_len, LPSTR buffer )
|
|
{
|
|
UNICODE_STRING str;
|
|
NTSTATUS status;
|
|
WCHAR data[MAX_PATH];
|
|
DWORD len;
|
|
|
|
str.Buffer = data;
|
|
str.MaximumLength = sizeof(data);
|
|
|
|
for (;;)
|
|
{
|
|
status = LdrGetDllDirectory( &str );
|
|
if (status != STATUS_BUFFER_TOO_SMALL) break;
|
|
if (str.Buffer != data) HeapFree( GetProcessHeap(), 0, str.Buffer );
|
|
str.MaximumLength = str.Length;
|
|
if (!(str.Buffer = HeapAlloc( GetProcessHeap(), 0, str.MaximumLength )))
|
|
{
|
|
status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!set_ntstatus( status )) return 0;
|
|
|
|
len = FILE_name_WtoA( str.Buffer, str.Length / sizeof(WCHAR), NULL, 0 );
|
|
if (buffer && buf_len > len)
|
|
{
|
|
FILE_name_WtoA( str.Buffer, -1, buffer, buf_len );
|
|
}
|
|
else
|
|
{
|
|
len++; /* for terminating null */
|
|
if (buffer) *buffer = 0;
|
|
}
|
|
if (str.Buffer != data) HeapFree( GetProcessHeap(), 0, str.Buffer );
|
|
return len;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* GetDllDirectoryW (KERNEL32.@)
|
|
*/
|
|
DWORD WINAPI GetDllDirectoryW( DWORD buf_len, LPWSTR buffer )
|
|
{
|
|
UNICODE_STRING str;
|
|
NTSTATUS status;
|
|
|
|
str.Buffer = buffer;
|
|
str.MaximumLength = min( buf_len, UNICODE_STRING_MAX_CHARS ) * sizeof(WCHAR);
|
|
status = LdrGetDllDirectory( &str );
|
|
if (status == STATUS_BUFFER_TOO_SMALL) status = STATUS_SUCCESS;
|
|
if (!set_ntstatus( status )) return 0;
|
|
return str.Length / sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* SetDllDirectoryA (KERNEL32.@)
|
|
*/
|
|
BOOL WINAPI SetDllDirectoryA( LPCSTR dir )
|
|
{
|
|
WCHAR *dirW = NULL;
|
|
BOOL ret;
|
|
|
|
if (dir && !(dirW = FILE_name_AtoW( dir, TRUE ))) return FALSE;
|
|
ret = SetDllDirectoryW( dirW );
|
|
HeapFree( GetProcessHeap(), 0, dirW );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* SetDllDirectoryW (KERNEL32.@)
|
|
*/
|
|
BOOL WINAPI SetDllDirectoryW( LPCWSTR dir )
|
|
{
|
|
UNICODE_STRING str;
|
|
|
|
RtlInitUnicodeString( &str, dir );
|
|
return set_ntstatus( LdrSetDllDirectory( &str ));
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetBinaryTypeW [KERNEL32.@]
|
|
*
|
|
* 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 subsystem an
|
|
* executable file runs under. lpBinaryType can be set to one of the following
|
|
* values:
|
|
* SCS_32BIT_BINARY: A Win32 based application
|
|
* SCS_64BIT_BINARY: A Win64 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, 32 or 64 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.
|
|
*/
|
|
BOOL WINAPI GetBinaryTypeW( LPCWSTR name, LPDWORD type )
|
|
{
|
|
static const WCHAR comW[] = { '.','c','o','m',0 };
|
|
static const WCHAR pifW[] = { '.','p','i','f',0 };
|
|
HANDLE hfile, mapping;
|
|
NTSTATUS status;
|
|
const WCHAR *ptr;
|
|
|
|
TRACE("%s\n", debugstr_w(name) );
|
|
|
|
if (type == NULL) return FALSE;
|
|
|
|
hfile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
|
|
if ( hfile == INVALID_HANDLE_VALUE )
|
|
return FALSE;
|
|
|
|
status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY,
|
|
NULL, NULL, PAGE_READONLY, SEC_IMAGE, hfile );
|
|
CloseHandle( hfile );
|
|
|
|
switch (status)
|
|
{
|
|
case STATUS_SUCCESS:
|
|
{
|
|
SECTION_IMAGE_INFORMATION info;
|
|
|
|
status = NtQuerySection( mapping, SectionImageInformation, &info, sizeof(info), NULL );
|
|
CloseHandle( mapping );
|
|
if (status) return FALSE;
|
|
switch (info.Machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
case IMAGE_FILE_MACHINE_ARM:
|
|
case IMAGE_FILE_MACHINE_THUMB:
|
|
case IMAGE_FILE_MACHINE_ARMNT:
|
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|
*type = SCS_32BIT_BINARY;
|
|
return TRUE;
|
|
case IMAGE_FILE_MACHINE_AMD64:
|
|
case IMAGE_FILE_MACHINE_ARM64:
|
|
*type = SCS_64BIT_BINARY;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
case STATUS_INVALID_IMAGE_WIN_16:
|
|
*type = SCS_WOW_BINARY;
|
|
return TRUE;
|
|
case STATUS_INVALID_IMAGE_WIN_32:
|
|
*type = SCS_32BIT_BINARY;
|
|
return TRUE;
|
|
case STATUS_INVALID_IMAGE_WIN_64:
|
|
*type = SCS_64BIT_BINARY;
|
|
return TRUE;
|
|
case STATUS_INVALID_IMAGE_NE_FORMAT:
|
|
*type = SCS_OS216_BINARY;
|
|
return TRUE;
|
|
case STATUS_INVALID_IMAGE_PROTECT:
|
|
*type = SCS_DOS_BINARY;
|
|
return TRUE;
|
|
case STATUS_INVALID_IMAGE_NOT_MZ:
|
|
if ((ptr = wcsrchr( name, '.' )))
|
|
{
|
|
if (!wcsicmp( ptr, comW ))
|
|
{
|
|
*type = SCS_DOS_BINARY;
|
|
return TRUE;
|
|
}
|
|
if (!wcsicmp( ptr, pifW ))
|
|
{
|
|
*type = SCS_PIF_BINARY;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetBinaryTypeA [KERNEL32.@]
|
|
* GetBinaryType [KERNEL32.@]
|
|
*
|
|
* See GetBinaryTypeW.
|
|
*/
|
|
BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
|
|
{
|
|
ANSI_STRING app_nameA;
|
|
|
|
TRACE("%s\n", debugstr_a(lpApplicationName));
|
|
|
|
/* Sanity check.
|
|
*/
|
|
if ( lpApplicationName == NULL || lpBinaryType == NULL )
|
|
return FALSE;
|
|
|
|
RtlInitAnsiString(&app_nameA, lpApplicationName);
|
|
if (!set_ntstatus( RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString,
|
|
&app_nameA, FALSE )))
|
|
return FALSE;
|
|
return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetProcAddress (KERNEL32.@)
|
|
*
|
|
* 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.
|
|
*/
|
|
FARPROC get_proc_address( HMODULE hModule, LPCSTR function )
|
|
{
|
|
FARPROC fp;
|
|
|
|
if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
|
|
|
|
if ((ULONG_PTR)function >> 16)
|
|
{
|
|
ANSI_STRING str;
|
|
|
|
RtlInitAnsiString( &str, function );
|
|
if (!set_ntstatus( LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp ))) return NULL;
|
|
}
|
|
else
|
|
if (!set_ntstatus( LdrGetProcedureAddress( hModule, NULL, LOWORD(function), (void**)&fp )))
|
|
return NULL;
|
|
|
|
return fp;
|
|
}
|
|
|
|
#ifdef __x86_64__
|
|
/*
|
|
* Work around a Delphi bug on x86_64. When delay loading a symbol,
|
|
* Delphi saves rcx, rdx, r8 and r9 to the stack. It then calls
|
|
* GetProcAddress(), pops the saved registers and calls the function.
|
|
* This works fine if all of the parameters are ints. However, since
|
|
* it does not save xmm0 - 3, it relies on GetProcAddress() preserving
|
|
* these registers if the function takes floating point parameters.
|
|
* This wrapper saves xmm0 - 3 to the stack.
|
|
*/
|
|
extern FARPROC get_proc_address_wrapper( HMODULE module, LPCSTR function );
|
|
|
|
__ASM_GLOBAL_FUNC( get_proc_address_wrapper,
|
|
"pushq %rbp\n\t"
|
|
__ASM_SEH(".seh_pushreg %rbp\n\t")
|
|
__ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
|
|
__ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
|
|
"movq %rsp,%rbp\n\t"
|
|
__ASM_SEH(".seh_setframe %rbp,0\n\t")
|
|
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
|
|
__ASM_SEH(".seh_endprologue\n\t")
|
|
"subq $0x60,%rsp\n\t"
|
|
"andq $~15,%rsp\n\t"
|
|
"movaps %xmm0,0x20(%rsp)\n\t"
|
|
"movaps %xmm1,0x30(%rsp)\n\t"
|
|
"movaps %xmm2,0x40(%rsp)\n\t"
|
|
"movaps %xmm3,0x50(%rsp)\n\t"
|
|
"call " __ASM_NAME("get_proc_address") "\n\t"
|
|
"movaps 0x50(%rsp), %xmm3\n\t"
|
|
"movaps 0x40(%rsp), %xmm2\n\t"
|
|
"movaps 0x30(%rsp), %xmm1\n\t"
|
|
"movaps 0x20(%rsp), %xmm0\n\t"
|
|
"leaq 0(%rbp),%rsp\n\t"
|
|
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
|
|
"popq %rbp\n\t"
|
|
__ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
|
|
__ASM_CFI(".cfi_same_value %rbp\n\t")
|
|
"ret" )
|
|
#else /* __x86_64__ */
|
|
|
|
static inline FARPROC get_proc_address_wrapper( HMODULE module, LPCSTR function )
|
|
{
|
|
return get_proc_address( module, function );
|
|
}
|
|
|
|
#endif /* __x86_64__ */
|
|
|
|
FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
|
|
{
|
|
return get_proc_address_wrapper( hModule, function );
|
|
}
|