ntdll: Move the current directory initialization to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c1dc5021ac
commit
df5e476487
|
@ -306,58 +306,3 @@ BOOLEAN WINAPI RtlDoesFileExists_U(LPCWSTR file_name)
|
||||||
RtlFreeUnicodeString( &nt_name );
|
RtlFreeUnicodeString( &nt_name );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* DIR_get_unix_cwd
|
|
||||||
*
|
|
||||||
* Retrieve the Unix name of the current directory; helper for wine_unix_to_nt_file_name.
|
|
||||||
* Returned value must be freed by caller.
|
|
||||||
*/
|
|
||||||
NTSTATUS DIR_get_unix_cwd( char **cwd )
|
|
||||||
{
|
|
||||||
CURDIR *curdir;
|
|
||||||
HANDLE handle;
|
|
||||||
NTSTATUS status;
|
|
||||||
ANSI_STRING name;
|
|
||||||
|
|
||||||
RtlAcquirePebLock();
|
|
||||||
|
|
||||||
if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */
|
|
||||||
curdir = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir;
|
|
||||||
else
|
|
||||||
curdir = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory;
|
|
||||||
|
|
||||||
if (!(handle = curdir->Handle))
|
|
||||||
{
|
|
||||||
UNICODE_STRING dirW;
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( curdir->DosPath.Buffer, &dirW, NULL, NULL ))
|
|
||||||
{
|
|
||||||
status = STATUS_OBJECT_NAME_INVALID;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
attr.Length = sizeof(attr);
|
|
||||||
attr.RootDirectory = 0;
|
|
||||||
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
||||||
attr.ObjectName = &dirW;
|
|
||||||
attr.SecurityDescriptor = NULL;
|
|
||||||
attr.SecurityQualityOfService = NULL;
|
|
||||||
|
|
||||||
status = NtOpenFile( &handle, SYNCHRONIZE, &attr, &io, 0,
|
|
||||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
|
||||||
RtlFreeUnicodeString( &dirW );
|
|
||||||
if (status != STATUS_SUCCESS) goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = server_get_unix_name( handle, &name );
|
|
||||||
if (!status) *cwd = name.Buffer;
|
|
||||||
|
|
||||||
if (!curdir->Handle) NtClose( handle );
|
|
||||||
|
|
||||||
done:
|
|
||||||
RtlReleasePebLock();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
|
@ -574,69 +574,13 @@ char **build_envp( const WCHAR *envW )
|
||||||
*/
|
*/
|
||||||
static void get_current_directory( UNICODE_STRING *dir )
|
static void get_current_directory( UNICODE_STRING *dir )
|
||||||
{
|
{
|
||||||
const char *pwd;
|
unix_funcs->get_initial_directory( dir );
|
||||||
char *cwd;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
dir->Length = 0;
|
|
||||||
|
|
||||||
/* try to get it from the Unix cwd */
|
|
||||||
|
|
||||||
for (size = 1024; ; size *= 2)
|
|
||||||
{
|
|
||||||
if (!(cwd = RtlAllocateHeap( GetProcessHeap(), 0, size ))) break;
|
|
||||||
if (getcwd( cwd, size )) break;
|
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, cwd );
|
|
||||||
if (errno == ERANGE) continue;
|
|
||||||
cwd = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try to use PWD if it is valid, so that we don't resolve symlinks */
|
|
||||||
|
|
||||||
pwd = getenv( "PWD" );
|
|
||||||
if (cwd)
|
|
||||||
{
|
|
||||||
struct stat st1, st2;
|
|
||||||
|
|
||||||
if (!pwd || stat( pwd, &st1 ) == -1 ||
|
|
||||||
(!stat( cwd, &st2 ) && (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)))
|
|
||||||
pwd = cwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pwd)
|
|
||||||
{
|
|
||||||
ANSI_STRING unix_name;
|
|
||||||
UNICODE_STRING nt_name;
|
|
||||||
|
|
||||||
RtlInitAnsiString( &unix_name, pwd );
|
|
||||||
if (!wine_unix_to_nt_file_name( &unix_name, &nt_name ))
|
|
||||||
{
|
|
||||||
/* skip the \??\ prefix */
|
|
||||||
if (nt_name.Length > 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':')
|
|
||||||
{
|
|
||||||
dir->Length = nt_name.Length - 4 * sizeof(WCHAR);
|
|
||||||
memcpy( dir->Buffer, nt_name.Buffer + 4, dir->Length );
|
|
||||||
}
|
|
||||||
else /* change \??\ to \\?\ */
|
|
||||||
{
|
|
||||||
dir->Length = nt_name.Length;
|
|
||||||
memcpy( dir->Buffer, nt_name.Buffer, dir->Length );
|
|
||||||
dir->Buffer[1] = '\\';
|
|
||||||
}
|
|
||||||
RtlFreeUnicodeString( &nt_name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dir->Length) /* still not initialized */
|
if (!dir->Length) /* still not initialized */
|
||||||
{
|
{
|
||||||
MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
|
|
||||||
"starting in the Windows directory.\n", cwd ? cwd : "" );
|
|
||||||
dir->Length = wcslen( windows_dir ) * sizeof(WCHAR);
|
dir->Length = wcslen( windows_dir ) * sizeof(WCHAR);
|
||||||
memcpy( dir->Buffer, windows_dir, dir->Length );
|
memcpy( dir->Buffer, windows_dir, dir->Length );
|
||||||
}
|
}
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, cwd );
|
|
||||||
|
|
||||||
/* add trailing backslash */
|
/* add trailing backslash */
|
||||||
if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\')
|
if (dir->Buffer[dir->Length / sizeof(WCHAR) - 1] != '\\')
|
||||||
{
|
{
|
||||||
|
@ -1550,6 +1494,5 @@ done:
|
||||||
RtlInitUnicodeString( &curdir, windows_dir );
|
RtlInitUnicodeString( &curdir, windows_dir );
|
||||||
RtlSetCurrentDirectory_U( &curdir );
|
RtlSetCurrentDirectory_U( &curdir );
|
||||||
}
|
}
|
||||||
if (!params->CurrentDirectory.Handle) chdir("/"); /* avoid locking removable devices */
|
|
||||||
set_wow64_environment( ¶ms->Environment );
|
set_wow64_environment( ¶ms->Environment );
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,6 @@ extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN;
|
extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
|
extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
|
||||||
extern void init_directories(void) DECLSPEC_HIDDEN;
|
extern void init_directories(void) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS DIR_get_unix_cwd( char **cwd ) DECLSPEC_HIDDEN;
|
|
||||||
extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) DECLSPEC_HIDDEN;
|
extern unsigned int DIR_get_drives_info( struct drive_info info[MAX_DOS_DRIVES] ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
/* virtual memory */
|
/* virtual memory */
|
||||||
|
|
|
@ -854,6 +854,75 @@ NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *siz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* get_initial_directory
|
||||||
|
*
|
||||||
|
* Get the current directory at startup.
|
||||||
|
*/
|
||||||
|
void CDECL get_initial_directory( UNICODE_STRING *dir )
|
||||||
|
{
|
||||||
|
const char *pwd;
|
||||||
|
char *cwd;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
dir->Length = 0;
|
||||||
|
|
||||||
|
/* try to get it from the Unix cwd */
|
||||||
|
|
||||||
|
for (size = 1024; ; size *= 2)
|
||||||
|
{
|
||||||
|
if (!(cwd = malloc( size ))) break;
|
||||||
|
if (getcwd( cwd, size )) break;
|
||||||
|
free( cwd );
|
||||||
|
if (errno == ERANGE) continue;
|
||||||
|
cwd = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to use PWD if it is valid, so that we don't resolve symlinks */
|
||||||
|
|
||||||
|
pwd = getenv( "PWD" );
|
||||||
|
if (cwd)
|
||||||
|
{
|
||||||
|
struct stat st1, st2;
|
||||||
|
|
||||||
|
if (!pwd || stat( pwd, &st1 ) == -1 ||
|
||||||
|
(!stat( cwd, &st2 ) && (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)))
|
||||||
|
pwd = cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwd)
|
||||||
|
{
|
||||||
|
ANSI_STRING unix_name;
|
||||||
|
UNICODE_STRING nt_name;
|
||||||
|
|
||||||
|
RtlInitAnsiString( &unix_name, pwd );
|
||||||
|
if (!unix_to_nt_file_name( &unix_name, &nt_name ))
|
||||||
|
{
|
||||||
|
/* skip the \??\ prefix */
|
||||||
|
if (nt_name.Length > 6 * sizeof(WCHAR) && nt_name.Buffer[5] == ':')
|
||||||
|
{
|
||||||
|
dir->Length = nt_name.Length - 4 * sizeof(WCHAR);
|
||||||
|
memcpy( dir->Buffer, nt_name.Buffer + 4, dir->Length );
|
||||||
|
}
|
||||||
|
else /* change \??\ to \\?\ */
|
||||||
|
{
|
||||||
|
dir->Length = nt_name.Length;
|
||||||
|
memcpy( dir->Buffer, nt_name.Buffer, dir->Length );
|
||||||
|
dir->Buffer[1] = '\\';
|
||||||
|
}
|
||||||
|
RtlFreeUnicodeString( &nt_name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir->Length) /* still not initialized */
|
||||||
|
MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
|
||||||
|
"starting in the Windows directory.\n", cwd ? cwd : "" );
|
||||||
|
free( cwd );
|
||||||
|
chdir( "/" ); /* avoid locking removable devices */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* get_unix_codepage
|
* get_unix_codepage
|
||||||
*
|
*
|
||||||
|
|
|
@ -951,6 +951,7 @@ static struct unix_funcs unix_funcs =
|
||||||
fast_RtlWakeConditionVariable,
|
fast_RtlWakeConditionVariable,
|
||||||
get_main_args,
|
get_main_args,
|
||||||
get_initial_environment,
|
get_initial_environment,
|
||||||
|
get_initial_directory,
|
||||||
get_paths,
|
get_paths,
|
||||||
get_dll_path,
|
get_dll_path,
|
||||||
get_unix_codepage,
|
get_unix_codepage,
|
||||||
|
|
|
@ -481,18 +481,26 @@ static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **win
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* get_unix_curdir
|
* get_unix_curdir
|
||||||
*/
|
*/
|
||||||
static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
|
static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
|
||||||
{
|
{
|
||||||
UNICODE_STRING nt_name;
|
UNICODE_STRING nt_name;
|
||||||
ANSI_STRING unix_name;
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
HANDLE handle;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( params->CurrentDirectory.DosPath.Buffer, &nt_name, NULL, NULL ))
|
if (!RtlDosPathNameToNtPathName_U( params->CurrentDirectory.DosPath.Buffer, &nt_name, NULL, NULL ))
|
||||||
return NULL;
|
return -1;
|
||||||
status = nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN_IF, FALSE );
|
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||||
|
status = NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||||
RtlFreeUnicodeString( &nt_name );
|
RtlFreeUnicodeString( &nt_name );
|
||||||
if (status && status != STATUS_NO_SUCH_FILE) return NULL;
|
if (status) return -1;
|
||||||
return unix_name.Buffer;
|
server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
|
||||||
|
NtClose( handle );
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -519,8 +527,8 @@ static void set_stdio_fd( int stdin_fd, int stdout_fd )
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* spawn_process
|
* spawn_process
|
||||||
*/
|
*/
|
||||||
NTSTATUS CDECL spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
|
static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
|
||||||
const char *unixdir, char *winedebug, const pe_image_info_t *pe_info )
|
int unixdir, char *winedebug, const pe_image_info_t *pe_info )
|
||||||
{
|
{
|
||||||
const int is_child_64bit = (pe_info->cpu == CPU_x86_64 || pe_info->cpu == CPU_ARM64);
|
const int is_child_64bit = (pe_info->cpu == CPU_x86_64 || pe_info->cpu == CPU_ARM64);
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
@ -548,8 +556,11 @@ NTSTATUS CDECL spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int soc
|
||||||
if (stdout_fd != -1) close( stdout_fd );
|
if (stdout_fd != -1) close( stdout_fd );
|
||||||
|
|
||||||
if (winedebug) putenv( winedebug );
|
if (winedebug) putenv( winedebug );
|
||||||
if (unixdir) chdir( unixdir );
|
if (unixdir != -1)
|
||||||
|
{
|
||||||
|
fchdir( unixdir );
|
||||||
|
close( unixdir );
|
||||||
|
}
|
||||||
argv = build_argv( ¶ms->CommandLine, 2 );
|
argv = build_argv( ¶ms->CommandLine, 2 );
|
||||||
|
|
||||||
exec_wineloader( argv, socketfd, is_child_64bit,
|
exec_wineloader( argv, socketfd, is_child_64bit,
|
||||||
|
@ -630,7 +641,7 @@ NTSTATUS CDECL exec_process( const UNICODE_STRING *cmdline, const pe_image_info_
|
||||||
*
|
*
|
||||||
* Fork and exec a new Unix binary, checking for errors.
|
* Fork and exec a new Unix binary, checking for errors.
|
||||||
*/
|
*/
|
||||||
static NTSTATUS fork_and_exec( UNICODE_STRING *path, const char *unix_dir,
|
static NTSTATUS fork_and_exec( UNICODE_STRING *path, int unixdir,
|
||||||
const RTL_USER_PROCESS_PARAMETERS *params )
|
const RTL_USER_PROCESS_PARAMETERS *params )
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -681,8 +692,11 @@ static NTSTATUS fork_and_exec( UNICODE_STRING *path, const char *unix_dir,
|
||||||
|
|
||||||
argv = build_argv( ¶ms->CommandLine, 0 );
|
argv = build_argv( ¶ms->CommandLine, 0 );
|
||||||
envp = build_envp( params->Environment );
|
envp = build_envp( params->Environment );
|
||||||
if (unix_dir) chdir( unix_dir );
|
if (unixdir != -1)
|
||||||
|
{
|
||||||
|
fchdir( unixdir );
|
||||||
|
close( unixdir );
|
||||||
|
}
|
||||||
execve( unix_name.Buffer, argv, envp );
|
execve( unix_name.Buffer, argv, envp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,10 +755,10 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
|
HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
|
||||||
struct object_attributes *objattr;
|
struct object_attributes *objattr;
|
||||||
data_size_t attr_len;
|
data_size_t attr_len;
|
||||||
char *unixdir = NULL, *winedebug = NULL;
|
char *winedebug = NULL;
|
||||||
startup_info_t *startup_info = NULL;
|
startup_info_t *startup_info = NULL;
|
||||||
ULONG startup_info_size, env_size;
|
ULONG startup_info_size, env_size;
|
||||||
int socketfd[2] = { -1, -1 };
|
int unixdir, socketfd[2] = { -1, -1 };
|
||||||
pe_image_info_t pe_info;
|
pe_image_info_t pe_info;
|
||||||
CLIENT_ID id;
|
CLIENT_ID id;
|
||||||
HANDLE parent = 0, debug = 0, token = 0;
|
HANDLE parent = 0, debug = 0, token = 0;
|
||||||
|
@ -943,9 +957,9 @@ done:
|
||||||
if (process_handle) NtClose( process_handle );
|
if (process_handle) NtClose( process_handle );
|
||||||
if (thread_handle) NtClose( thread_handle );
|
if (thread_handle) NtClose( thread_handle );
|
||||||
if (socketfd[0] != -1) close( socketfd[0] );
|
if (socketfd[0] != -1) close( socketfd[0] );
|
||||||
|
if (unixdir != -1) close( unixdir );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, startup_info );
|
RtlFreeHeap( GetProcessHeap(), 0, startup_info );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, winedebug );
|
RtlFreeHeap( GetProcessHeap(), 0, winedebug );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, unixdir );
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T s
|
||||||
int top_down ) DECLSPEC_HIDDEN;
|
int top_down ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN;
|
extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN;
|
extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN;
|
||||||
|
extern void CDECL get_initial_directory( UNICODE_STRING *dir ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN;
|
extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN;
|
extern void CDECL get_locales( WCHAR *sys, WCHAR *user ) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size,
|
extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size,
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct ldt_copy;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
|
|
||||||
/* increment this when you change the function table */
|
/* increment this when you change the function table */
|
||||||
#define NTDLL_UNIXLIB_VERSION 51
|
#define NTDLL_UNIXLIB_VERSION 52
|
||||||
|
|
||||||
struct unix_funcs
|
struct unix_funcs
|
||||||
{
|
{
|
||||||
|
@ -259,6 +259,7 @@ struct unix_funcs
|
||||||
/* environment functions */
|
/* environment functions */
|
||||||
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
|
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
|
||||||
NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size );
|
NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size );
|
||||||
|
void (CDECL *get_initial_directory)( UNICODE_STRING *dir );
|
||||||
void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir );
|
void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir );
|
||||||
void (CDECL *get_dll_path)( const char ***paths, SIZE_T *maxlen );
|
void (CDECL *get_dll_path)( const char ***paths, SIZE_T *maxlen );
|
||||||
void (CDECL *get_unix_codepage)( CPTABLEINFO *table );
|
void (CDECL *get_unix_codepage)( CPTABLEINFO *table );
|
||||||
|
|
Loading…
Reference in New Issue