2025-04-28 12:25:20 +08:00

172 lines
3.1 KiB
C++

/**
* @file Minimal emulation of POSIX dlopen/dlsym/dlclose on Windows.
* @license Public domain.
*
* This code works fine for the common scenario of loading a
* specific DLL and calling one (or more) functions within it.
*
* No attempt is made to emulate POSIX symbol table semantics.
* The way Windows thinks about dynamic linking is fundamentally
* different, and there's no way to emulate the useful aspects of
* POSIX semantics.
*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "win32-dlfcn.h"
/**
* Win32 error code from last failure.
*/
static DWORD lastError = 0;
#ifdef __cplusplus
extern "C" {
#endif
/**
* Convert UTF-8 string to Windows UNICODE (UCS-2 LE).
*
* Caller must free() the returned string.
*/
static
WCHAR*
UTF8toWCHAR(
const char* inputString /** UTF-8 string. */
)
{
int outputSize;
WCHAR* outputString;
outputSize = MultiByteToWideChar(CP_UTF8, 0, inputString, -1, NULL, 0);
if (outputSize == 0)
return NULL;
outputString = (WCHAR*) malloc(outputSize * sizeof(WCHAR));
if (outputString == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
if (MultiByteToWideChar(CP_UTF8, 0, inputString, -1, outputString, outputSize) != outputSize)
{
free(outputString);
return NULL;
}
return outputString;
}
/**
* Open DLL, returning a handle.
*/
void*
dlopen(
const char* file, /** DLL filename (UTF-8). */
int mode /** mode flags (ignored). */
)
{
WCHAR* unicodeFilename;
UINT errorMode;
void* handle;
UNREFERENCED_PARAMETER(mode);
if (file == NULL)
return (void*) GetModuleHandle(NULL);
unicodeFilename = UTF8toWCHAR(file);
if (unicodeFilename == NULL) {
lastError = GetLastError();
return NULL;
}
errorMode = GetErrorMode();
/* Have LoadLibrary return NULL on failure; prevent GUI error message. */
SetErrorMode(errorMode | SEM_FAILCRITICALERRORS);
handle = (void*) LoadLibraryW(unicodeFilename);
if (handle == NULL)
lastError = GetLastError();
SetErrorMode(errorMode);
free(unicodeFilename);
return handle;
}
/**
* Close DLL.
*/
int
dlclose(
void* handle /** Handle from dlopen(). */
)
{
int rc = 0;
if (handle != (void*) GetModuleHandle(NULL))
rc = !FreeLibrary((HMODULE) handle);
if (rc)
lastError = GetLastError();
return rc;
}
/**
* Look up symbol exported by DLL.
*/
void*
dlsym(
void* handle, /** Handle from dlopen(). */
const char* name /** Name of exported symbol (ASCII). */
)
{
void* address = (void*) GetProcAddress((HMODULE) handle, name);
if (address == NULL)
lastError = GetLastError();
return address;
}
/**
* Return message describing last error.
*/
char*
dlerror(void)
{
static char errorMessage[64];
if (lastError != 0) {
sprintf(errorMessage, "Win32 error %lu", lastError);
lastError = 0;
return errorMessage;
} else {
return NULL;
}
}
#ifdef __cplusplus
}
#endif