diff --git a/CMakeLists.txt b/CMakeLists.txt index 26b98ba3..ed6597d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,11 +183,10 @@ set(ARGON2_FILL_BLOCKS_SRC if (WIN32) set(SOURCES_OS - res/app.rc src/App_win.cpp src/base/io/Json_win.cpp src/common/Platform_win.cpp - ) + ) add_definitions(/DWIN32) set(EXTRA_LIBS ws2_32 psapi iphlpapi userenv) @@ -196,13 +195,13 @@ elseif (APPLE) src/App_unix.cpp src/base/io/Json_unix.cpp src/common/Platform_mac.cpp - ) + ) else() set(SOURCES_OS src/App_unix.cpp src/base/io/Json_unix.cpp src/common/Platform_unix.cpp - ) + ) if (CMAKE_SYSTEM_NAME STREQUAL FreeBSD) set(EXTRA_LIBS kvm pthread) @@ -295,9 +294,21 @@ if (WITH_DEBUG_LOG) add_definitions(/DAPP_DEBUG) endif() +if(WIN32) + add_definitions(/DRAPIDJSON_HAS_STDSTRING=1) + add_definitions(/DRAPIDJSON_HAS_CXX11_RVALUE_REFS=1) + + include_directories(src/win64/include) + list(APPEND SOURCES_COMMON src/win64/src/dlfcn.c) +endif() + add_library(argon2_common SHARED ${HEADERS_COMMON} ${SOURCES_COMMON}) target_link_libraries(argon2_common ${CMAKE_DL_LIBS}) +if(WIN32) + target_link_libraries(argon2_common Psapi.lib) +endif() + add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${TLS_SOURCES}) target_link_libraries(${CMAKE_PROJECT_NAME} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB} argon2_common) @@ -349,7 +360,7 @@ if(ARCH STREQUAL "arm" OR ARCH STREQUAL "aarch64") SUFFIX ".opt" LIBRARY_OUTPUT_DIRECTORY modules ) - target_compile_options(common PRIVATE -D__NEON__) + target_compile_options(argon2_common PRIVATE -D__NEON__) if(ARCH STREQUAL "arm") target_compile_options(argon2_fill_blocks_NEON PRIVATE -D__NEON__ -mfpu=neon -funsafe-math-optimizations) else() diff --git a/src/3rdparty/rapidjson/document.h b/src/3rdparty/rapidjson/document.h index e3e20dfb..20dae591 100644 --- a/src/3rdparty/rapidjson/document.h +++ b/src/3rdparty/rapidjson/document.h @@ -29,6 +29,8 @@ RAPIDJSON_DIAG_PUSH #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#undef min //visual studio declares min as macro which fails when compiling numeric_limits::min and max calls +#undef max #endif #ifdef __clang__ diff --git a/src/base/tools/String.cpp b/src/base/tools/String.cpp index ccffc2a8..7a2e7e60 100644 --- a/src/base/tools/String.cpp +++ b/src/base/tools/String.cpp @@ -67,6 +67,10 @@ xmrig::String::String(const String &other) : memcpy(m_data, other.m_data, m_size + 1); } +#ifdef _MSC_VER +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif bool xmrig::String::isEqual(const char *str, bool caseInsensitive) const { diff --git a/src/common/log/FileLog.cpp b/src/common/log/FileLog.cpp index 9134c7c7..fbfca241 100644 --- a/src/common/log/FileLog.cpp +++ b/src/common/log/FileLog.cpp @@ -28,6 +28,8 @@ #include #include +#include +#include #include "common/log/FileLog.h" #include "common/log/Log.h" diff --git a/src/common/net/Client.cpp b/src/common/net/Client.cpp index 7cd09d46..c7bc91de 100644 --- a/src/common/net/Client.cpp +++ b/src/common/net/Client.cpp @@ -29,6 +29,10 @@ #include #include +#ifdef _MSC_VER +#define strncasecmp(x,y,z) _strnicmp(x,y,z) +#include +#endif #ifndef XMRIG_NO_TLS # include @@ -36,7 +40,6 @@ # include "common/net/Tls.h" #endif - #include "common/interfaces/IClientListener.h" #include "common/log/Log.h" #include "common/net/Client.h" @@ -47,11 +50,6 @@ #include "rapidjson/writer.h" -#ifdef _MSC_VER -# define strncasecmp(x,y,z) _strnicmp(x,y,z) -#endif - - namespace xmrig { int64_t Client::m_sequence = 1; diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 7ddb5d70..3b371e04 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -37,6 +37,10 @@ #include "rapidjson/prettywriter.h" #include "HasherConfig.h" +#ifdef _MSC_VER +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif static char affinity_tmp[20] = { 0 }; diff --git a/src/crypto/argon2_hasher/common/common.h b/src/crypto/argon2_hasher/common/common.h index 753716a0..dcd64c26 100755 --- a/src/crypto/argon2_hasher/common/common.h +++ b/src/crypto/argon2_hasher/common/common.h @@ -51,6 +51,6 @@ using namespace std; #define LOG(msg) cout< getFiles(const string &folder); +vector getFiles(const string &folder); #endif //ARGON2_COMMON_H diff --git a/src/crypto/argon2_hasher/hash/gpu/cuda/CudaHasher.cpp b/src/crypto/argon2_hasher/hash/gpu/cuda/CudaHasher.cpp index 2a384cb9..ebe5446f 100644 --- a/src/crypto/argon2_hasher/hash/gpu/cuda/CudaHasher.cpp +++ b/src/crypto/argon2_hasher/hash/gpu/cuda/CudaHasher.cpp @@ -292,7 +292,7 @@ bool CudaHasher::buildThreadData() { } #else thread_data.threadsIdx = 0; - thread_data.threads = device->profile_info.threads; + thread_data.threads = device->profileInfo.threads; #endif thread_data.argon2 = new Argon2(cuda_kernel_prehasher, cuda_kernel_filler, cuda_kernel_posthasher, diff --git a/src/crypto/argon2_hasher/hash/gpu/cuda/cuda_kernel.cu b/src/crypto/argon2_hasher/hash/gpu/cuda/cuda_kernel.cu index 312e35bf..c1f2d8a7 100644 --- a/src/crypto/argon2_hasher/hash/gpu/cuda/cuda_kernel.cu +++ b/src/crypto/argon2_hasher/hash/gpu/cuda/cuda_kernel.cu @@ -888,7 +888,7 @@ void cuda_allocate(CudaDeviceInfo *device, double chunks, size_t chunk_size) { #ifdef PARALLEL_CUDA int threads = device->profileInfo.threads / 2; #else - int threads = device->profile_info.threads; + int threads = device->profileInfo.threads; #endif size_t preseed_memory_size = profile->pwdLen * 4; diff --git a/src/win64/include/dirent.h b/src/win64/include/dirent.h new file mode 100644 index 00000000..78e1aab7 --- /dev/null +++ b/src/win64/include/dirent.h @@ -0,0 +1,1224 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 2006-2012 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +# define S_IFBLK 0 +#endif + +/* Link */ +#if !defined(S_IFLNK) +# define S_IFLNK 0 +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#if !defined(S_ISFIFO) +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + + +/* Dirent functions */ +static DIR *opendir (const char *dirname); +static _WDIR *_wopendir (const wchar_t *dirname); + +static struct dirent *readdir (DIR *dirp); +static struct _wdirent *_wreaddir (_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + +static int closedir (DIR *dirp); +static int _wclosedir (_WDIR *dirp); + +static void rewinddir (DIR* dirp); +static void _wrewinddir (_WDIR* dirp); + +static int scandir (const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort (const struct dirent **a, const struct dirent **b); + +static int versionsort (const struct dirent **a, const struct dirent **b); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); + +static int dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); + +static int dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno (int error); + + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR* +_wopendir( + const wchar_t *dirname) +{ + _WDIR *dirp = NULL; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (dirp != NULL) { + DWORD n; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + n = wcslen(dirname); +# else + n = GetFullPathNameW (dirname, 0, NULL, NULL); +# endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt) { + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + wcsncpy_s(dirp->patt, n+1, dirname, n); +# else + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); +# endif + if (n > 0) { + wchar_t *p; + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + if (dirp->patt < p) { + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (dirent_first (dirp)) { + /* Directory stream opened successfully */ + error = 0; + } else { + /* Cannot retrieve first entry */ + error = 1; + dirent_set_errno (ENOENT); + } + + } else { + /* Cannot retrieve full path name */ + dirent_set_errno (ENOENT); + error = 1; + } + + } else { + /* Cannot allocate memory for search pattern */ + error = 1; + } + + } else { + /* Cannot allocate _WDIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + _wclosedir (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent* +_wreaddir( + _WDIR *dirp) +{ + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) _wreaddir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, + struct _wdirent *entry, + struct _wdirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) { + size_t n; + DWORD attr; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; + n++; + } + entry->d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct _wdirent); + + /* Set result address */ + *result = entry; + + } else { + + /* Return NULL to indicate end of directory */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir( + _WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + } + + /* Release search pattern */ + if (dirp->patt) { + free (dirp->patt); + dirp->patt = NULL; + } + + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void +_wrewinddir( + _WDIR* dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Open new search handle */ + dirent_first (dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_first( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + + } else { + + /* Failed to re-open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + + } + return datap; +} + +/* + * Get next directory entry (internal). + * + * Returns + */ +static WIN32_FIND_DATAW* +dirent_next( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + + } else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } else { + /* The very last entry has been processed or an error occurred */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + + } else { + + /* End of directory stream reached */ + p = NULL; + + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR* +opendir( + const char *dirname) +{ + struct DIR *dirp; + int error; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (dirp) { + wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (!error) { + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (dirp->wdirp) { + /* Directory stream opened */ + error = 0; + } else { + /* Failed to open directory stream */ + error = 1; + } + + } else { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + error = 1; + } + + } else { + /* Cannot allocate DIR structure */ + error = 1; + } + + /* Clean up in case of error */ + if (error && dirp) { + free (dirp); + dirp = NULL; + } + + return dirp; +} + +/* + * Read next directory entry. + */ +static struct dirent* +readdir( + DIR *dirp) +{ + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) readdir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, + struct dirent *entry, + struct dirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + DWORD attr; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct dirent); + + } else { + + /* + * Cannot convert file name to multi-byte string so construct + * an erroneous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + + } + + /* Return pointer to directory entry */ + *result = entry; + + } else { + + /* No more directory entries */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream. + */ +static int +closedir( + DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free (dirp); + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void +rewinddir( + DIR* dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); +} + +/* + * Scan directory for entries. + */ +static int +scandir( + const char *dirname, + struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir (dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc (files, sizeof (void*) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } else { + /* Out of memory */ + result = -1; + break; + } + + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent*) malloc (sizeof (struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r (dir, tmp, &entry) == /*OK*/0) { + + /* Did we get an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter (tmp); + } else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + + } else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort (files, size, sizeof (void*), + (int (*) (const void*, const void*)) compare); + break; + + } + + } else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + + } + + } else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + if (tmp) { + free (tmp); + } + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free (files[i]); + } + free (files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir (dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int +alphasort( + const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort( + const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort (a, b); +} + +/* Convert multi-byte string to wide character string */ +static int +dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) +{ + int error; + int n; + size_t len; + UINT cp; + DWORD flags; + + /* Determine code page for multi-byte string */ + if (AreFileApisANSI ()) { + /* Default ANSI code page */ + cp = GetACP (); + } else { + /* Default OEM code page */ + cp = GetOEMCP (); + } + + /* + * Determine flags based on the character set. For more information, + * please see https://docs.microsoft.com/fi-fi/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar + */ + switch (cp) { + case 42: + case 50220: + case 50221: + case 50222: + case 50225: + case 50227: + case 50229: + case 57002: + case 57003: + case 57004: + case 57005: + case 57006: + case 57007: + case 57008: + case 57009: + case 57010: + case 57011: + case 65000: + /* MultiByteToWideChar does not support MB_ERR_INVALID_CHARS */ + flags = 0; + break; + + default: + /* + * Ask MultiByteToWideChar to return an error if a multi-byte + * character cannot be converted to a wide-character. + */ + flags = MB_ERR_INVALID_CHARS; + } + + /* Compute the length of input string without zero-terminator */ + len = 0; + while (mbstr[len] != '\0' && len < count) { + len++; + } + + /* Convert to wide-character string */ + n = MultiByteToWideChar( + /* Source code page */ cp, + /* Flags */ flags, + /* Pointer to string to convert */ mbstr, + /* Size of multi-byte string */ (int) len, + /* Pointer to output buffer */ wcstr, + /* Size of output buffer */ sizeInWords - 1 + ); + + /* Ensure that output buffer is zero-terminated */ + wcstr[n] = '\0'; + + /* Return length of wide-character string with zero-terminator */ + *pReturnValue = (size_t) (n + 1); + + /* Return zero if conversion succeeded */ + if (n > 0) { + error = 0; + } else { + error = 1; + } + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int +dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, + size_t count) +{ + int n; + int error; + UINT cp; + size_t len; + BOOL flag = 0; + LPBOOL pflag; + + /* Determine code page for multi-byte string */ + if (AreFileApisANSI ()) { + /* Default ANSI code page */ + cp = GetACP (); + } else { + /* Default OEM code page */ + cp = GetOEMCP (); + } + + /* Compute the length of input string without zero-terminator */ + len = 0; + while (wcstr[len] != '\0' && len < count) { + len++; + } + + /* + * Determine if we can ask WideCharToMultiByte to return information on + * broken characters. For more information, please see + * https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-widechartomultibyte + */ + switch (cp) { + case CP_UTF7: + case CP_UTF8: + /* + * WideCharToMultiByte fails if we request information on default + * characters. This is just a nuisance but doesn't affect the + * conversion: if Windows is configured to use UTF-8, then the default + * character should not be needed anyway. + */ + pflag = NULL; + break; + + default: + /* + * Request that WideCharToMultiByte sets the flag if it uses the + * default character. + */ + pflag = &flag; + } + + /* Convert wide-character string to multi-byte character string */ + n = WideCharToMultiByte( + /* Target code page */ cp, + /* Flags */ 0, + /* Pointer to unicode string */ wcstr, + /* Length of unicode string */ (int) len, + /* Pointer to output buffer */ mbstr, + /* Size of output buffer */ sizeInBytes - 1, + /* Default character */ NULL, + /* Whether default character was used or not */ pflag + ); + + /* Ensure that output buffer is zero-terminated */ + mbstr[n] = '\0'; + + /* Return length of multi-byte string with zero-terminator */ + *pReturnValue = (size_t) (n + 1); + + /* Return zero if conversion succeeded without using default characters */ + if (n > 0 && flag == 0) { + error = 0; + } else { + error = 1; + } + return error; +} + +/* Set errno variable */ +static void +dirent_set_errno( + int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno (error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/src/win64/include/dlfcn.h b/src/win64/include/dlfcn.h new file mode 100644 index 00000000..1eefd835 --- /dev/null +++ b/src/win64/include/dlfcn.h @@ -0,0 +1,59 @@ +/* + * dlfcn-win32 + * Copyright (c) 2007 Ramiro Polla + * + * dlfcn-win32 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. + * + * dlfcn-win32 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 dlfcn-win32; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DLFCN_H +#define DLFCN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(DLFCN_WIN32_EXPORTS) +# define DLFCN_EXPORT __declspec(dllexport) +#else +# define DLFCN_EXPORT +#endif + +/* POSIX says these are implementation-defined. + * To simplify use with Windows API, we treat them the same way. + */ + +#define RTLD_LAZY 0 +#define RTLD_NOW 0 + +#define RTLD_GLOBAL (1 << 1) +#define RTLD_LOCAL (1 << 2) + +/* These two were added in The Open Group Base Specifications Issue 6. + * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant. + */ + +#define RTLD_DEFAULT 0 +#define RTLD_NEXT 0 + +DLFCN_EXPORT void *dlopen ( const char *file, int mode ); +DLFCN_EXPORT int dlclose(void *handle); +DLFCN_EXPORT void *dlsym(void *handle, const char *name); +DLFCN_EXPORT char *dlerror(void); + +#ifdef __cplusplus +} +#endif + +#endif /* DLFCN_H */ diff --git a/src/win64/include/win64.h b/src/win64/include/win64.h new file mode 100644 index 00000000..d9e5529f --- /dev/null +++ b/src/win64/include/win64.h @@ -0,0 +1,12 @@ +// +// Created by Haifa Bogdan Adnan on 13/08/2018. +// + +#ifndef WIN64_COMPATIBILITY_LAYER_H +#define WIN64_COMPATIBILITY_LAYER_H + +//#include +#include +#include + +#endif //WIN64_COMPATIBILITY_LAYER_H diff --git a/src/win64/src/dlfcn.c b/src/win64/src/dlfcn.c new file mode 100644 index 00000000..617a70f9 --- /dev/null +++ b/src/win64/src/dlfcn.c @@ -0,0 +1,487 @@ +/* + * dlfcn-win32 + * Copyright (c) 2007 Ramiro Polla + * Copyright (c) 2015 Tiancheng "Timothy" Gu + * + * dlfcn-win32 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. + * + * dlfcn-win32 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 dlfcn-win32; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif +#define PSAPI_VERSION 1 +#include +#include +#include +#include + +#define DLFCN_WIN32_EXPORTS +#include "dlfcn.h" + +#if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) ) +#define snprintf sprintf_s +#endif + +#ifdef UNICODE +#include +#define CHAR wchar_t +#define UNICODE_L(s) L##s +#else +#define CHAR char +#define UNICODE_L(s) s +#endif + +/* Note: + * MSDN says these functions are not thread-safe. We make no efforts to have + * any kind of thread safety. + */ + +typedef struct global_object { + HMODULE hModule; + struct global_object *previous; + struct global_object *next; +} global_object; + +static global_object first_object; +static global_object first_automatic_object; +static int auto_ref_count = 0; + +/* These functions implement a double linked list for the global objects. */ +static global_object *global_search( global_object *start, HMODULE hModule ) +{ + global_object *pobject; + + if( hModule == NULL ) + return NULL; + + for( pobject = start; pobject; pobject = pobject->next ) + if( pobject->hModule == hModule ) + return pobject; + + return NULL; +} + +static void global_add( global_object *start, HMODULE hModule ) +{ + global_object *pobject; + global_object *nobject; + + if( hModule == NULL ) + return; + + pobject = global_search( start, hModule ); + + /* Do not add object again if it's already on the list */ + if( pobject ) + return; + + if( start == &first_automatic_object ) + { + pobject = global_search( &first_object, hModule ); + if( pobject ) + return; + } + + for( pobject = start; pobject->next; pobject = pobject->next ); + + nobject = (global_object*) malloc( sizeof( global_object ) ); + + /* Should this be enough to fail global_add, and therefore also fail + * dlopen? + */ + if( !nobject ) + return; + + pobject->next = nobject; + nobject->next = NULL; + nobject->previous = pobject; + nobject->hModule = hModule; +} + +static void global_rem( global_object *start, HMODULE hModule ) +{ + global_object *pobject; + + if( hModule == NULL ) + return; + + pobject = global_search( start, hModule ); + + if( !pobject ) + return; + + if( pobject->next ) + pobject->next->previous = pobject->previous; + if( pobject->previous ) + pobject->previous->next = pobject->next; + + free( pobject ); +} + +/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one + * static buffer. + * MSDN says the buffer cannot be larger than 64K bytes, so we set it to + * the limit. + */ +static CHAR error_buffer[65535]; +static CHAR *current_error; +static char dlerror_buffer[65536]; + +static int copy_string( CHAR *dest, int dest_size, const CHAR *src ) +{ + int i = 0; + + /* gcc should optimize this out */ + if( !src || !dest ) + return 0; + + for( i = 0 ; i < dest_size-1 ; i++ ) + { + if( !src[i] ) + break; + else + dest[i] = src[i]; + } + dest[i] = '\0'; + + return i; +} + +static void save_err_str( const CHAR *str ) +{ + DWORD dwMessageId; + DWORD pos; + + dwMessageId = GetLastError( ); + + if( dwMessageId == 0 ) + return; + + /* Format error message to: + * "": + */ + pos = copy_string( error_buffer, sizeof(error_buffer), UNICODE_L("\"") ); + pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str ); + pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, UNICODE_L("\": ") ); + pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId, + MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), + error_buffer+pos, sizeof(error_buffer)-pos, NULL ); + + if( pos > 1 ) + { + /* POSIX says the string must not have trailing */ + if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' ) + error_buffer[pos-2] = '\0'; + } + + current_error = error_buffer; +} + +static void save_err_ptr_str( const void *ptr ) +{ + CHAR ptr_buf[19]; /* 0x up to 64 bits. */ + +#ifdef UNICODE + +# if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) ) + swprintf_s( ptr_buf, 19, UNICODE_L("0x%p"), ptr ); +# else + swprintf(ptr_buf, 19, UNICODE_L("0x%p"), ptr); +# endif + +#else + snprintf( ptr_buf, 19, "0x%p", ptr ); +#endif + + save_err_str( ptr_buf ); +} + +void *dlopen( const char *file, int mode ) +{ + HMODULE hModule; + UINT uMode; + + current_error = NULL; + + /* Do not let Windows display the critical-error-handler message box */ + uMode = SetErrorMode( SEM_FAILCRITICALERRORS ); + + if( file == 0 ) + { + HMODULE hAddtnlMods[1024]; // Already loaded modules + HANDLE hCurrentProc = GetCurrentProcess( ); + DWORD cbNeeded; + + /* POSIX says that if the value of file is 0, a handle on a global + * symbol object must be provided. That object must be able to access + * all symbols from the original program file, and any objects loaded + * with the RTLD_GLOBAL flag. + * The return value from GetModuleHandle( ) allows us to retrieve + * symbols only from the original program file. For objects loaded with + * the RTLD_GLOBAL flag, we create our own list later on. For objects + * outside of the program file but already loaded (e.g. linked DLLs) + * they are added below. + */ + hModule = GetModuleHandle( NULL ); + + if( !hModule ) + save_err_ptr_str( file ); + + + /* GetModuleHandle( NULL ) only returns the current program file. So + * if we want to get ALL loaded module including those in linked DLLs, + * we have to use EnumProcessModules( ). + */ + if( EnumProcessModules( hCurrentProc, hAddtnlMods, + sizeof( hAddtnlMods ), &cbNeeded ) != 0 ) + { + DWORD i; + for( i = 0; i < cbNeeded / sizeof( HMODULE ); i++ ) + { + global_add( &first_automatic_object, hAddtnlMods[i] ); + } + } + auto_ref_count++; + } + else + { + CHAR lpFileName[MAX_PATH]; + int i; + + /* MSDN says backslashes *must* be used instead of forward slashes. */ + for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ ) + { + if( !file[i] ) + break; + else if( file[i] == '/' ) + lpFileName[i] = '\\'; + else + lpFileName[i] = file[i]; + } + lpFileName[i] = '\0'; + + /* POSIX says the search path is implementation-defined. + * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely + * to UNIX's search paths (start with system folders instead of current + * folder). + */ + hModule = LoadLibraryEx(lpFileName, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH ); + + /* If the object was loaded with RTLD_GLOBAL, add it to list of global + * objects, so that its symbols may be retrieved even if the handle for + * the original program file is passed. POSIX says that if the same + * file is specified in multiple invocations, and any of them are + * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the + * symbols will remain global. + */ + if( !hModule ) + save_err_str( lpFileName ); + else if( (mode & RTLD_GLOBAL) ) + global_add( &first_object, hModule ); + } + + /* Return to previous state of the error-mode bit flags. */ + SetErrorMode( uMode ); + + return (void *) hModule; +} + +static void free_auto( ) +{ + global_object *pobject = first_automatic_object.next; + if( pobject ) + { + global_object *next; + for ( ; pobject; pobject = next ) + { + next = pobject->next; + free( pobject ); + } + first_automatic_object.next = NULL; + } +} + +int dlclose( void *handle ) +{ + HMODULE hModule = (HMODULE) handle; + BOOL ret; + + current_error = NULL; + + ret = FreeLibrary( hModule ); + + /* If the object was loaded with RTLD_GLOBAL, remove it from list of global + * objects. + */ + if( ret ) + { + HMODULE cur = GetModuleHandle( NULL ); + global_rem( &first_object, hModule ); + if( hModule == cur ) + { + auto_ref_count--; + if( auto_ref_count < 0 ) + auto_ref_count = 0; + if( !auto_ref_count ) + free_auto( ); + } + } + else + save_err_ptr_str( handle ); + + /* dlclose's return value in inverted in relation to FreeLibrary's. */ + ret = !ret; + + return (int) ret; +} + +void *dlsym( void *handle, const char *name ) +{ + FARPROC symbol; + HMODULE hModule; + +#ifdef UNICODE + wchar_t namew[MAX_PATH]; + wmemset(namew, 0, MAX_PATH); +#endif + + current_error = NULL; + + symbol = GetProcAddress( (HMODULE) handle, name ); + + if( symbol != NULL ) + goto end; + + /* If the handle for the original program file is passed, also search + * in all globally loaded objects. + */ + + hModule = GetModuleHandle( NULL ); + + if( hModule == handle ) + { + global_object *pobject; + + for( pobject = &first_object; pobject; pobject = pobject->next ) + { + if( pobject->hModule ) + { + symbol = GetProcAddress( pobject->hModule, name ); + if( symbol != NULL ) + goto end; + } + } + + for( pobject = &first_automatic_object; pobject; pobject = pobject->next ) + { + if( pobject->hModule ) + { + symbol = GetProcAddress( pobject->hModule, name ); + if( symbol != NULL ) + goto end; + } + } + } + +end: + if( symbol == NULL ) + { +#ifdef UNICODE + size_t converted_chars; + + size_t str_len = strlen(name) + 1; + +#if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) ) + errno_t err = mbstowcs_s(&converted_chars, namew, str_len, name, str_len); + if (err != 0) + return NULL; +#else + mbstowcs(namew, name, str_len); +#endif + + save_err_str( namew ); +#else + save_err_str( name ); +#endif + } + + // warning C4054: 'type cast' : from function pointer 'FARPROC' to data pointer 'void *' +#ifdef _MSC_VER +#pragma warning( suppress: 4054 ) +#endif + return (void*) symbol; +} + +char *dlerror( void ) +{ + char *error_pointer = dlerror_buffer; + + /* If this is the second consecutive call to dlerror, return NULL */ + if (current_error == NULL) + { + return NULL; + } + +#ifdef UNICODE + errno_t err = 0; + size_t converted_chars = 0; + size_t str_len = wcslen(current_error) + 1; + memset(error_pointer, 0, 65535); + +# if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) ) + err = wcstombs_s(&converted_chars, + error_pointer, str_len * sizeof(char), + current_error, str_len * sizeof(wchar_t)); + + if (err != 0) + return NULL; +# else + wcstombs(error_pointer, current_error, str_len); +# endif + +#else + memcpy(error_pointer, current_error, strlen(current_error) + 1); +#endif + + /* POSIX says that invoking dlerror( ) a second time, immediately following + * a prior invocation, shall result in NULL being returned. + */ + current_error = NULL; + + return error_pointer; +} + +#ifdef SHARED +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +{ + (void) hinstDLL; + /* + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx + * + * When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap + * memory only if the DLL is being unloaded dynamically (the lpReserved + * parameter is NULL). + */ + if( fdwReason == DLL_PROCESS_DETACH && !lpvReserved ) + { + auto_ref_count = 0; + free_auto( ); + } + return TRUE; +} +#endif diff --git a/src/win64/tdr_delay.reg b/src/win64/tdr_delay.reg new file mode 100644 index 00000000..a2952e95 Binary files /dev/null and b/src/win64/tdr_delay.reg differ