diff --git a/configure/os/CONFIG.linux-x86.win32-x86-mingw b/configure/os/CONFIG.linux-x86.win32-x86-mingw index bd75f5ebd..655b33f23 100644 --- a/configure/os/CONFIG.linux-x86.win32-x86-mingw +++ b/configure/os/CONFIG.linux-x86.win32-x86-mingw @@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp +OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index a08f19902..8430011c4 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp +OP_SYS_LDLIBS = -lpsapi -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c index 6de3c428e..5731c8afe 100644 --- a/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c +++ b/modules/libcom/src/osi/os/WIN32/osdFindSymbol.c @@ -5,13 +5,33 @@ \*************************************************************************/ /* osi/os/WIN32/osdFindSymbol.c */ +/* Avoid need to link against psapi.dll. requires windows 7 or later. + * MinGW doesn't provide wrappers until 6.0, so fallback to psapi.dll + */ +#ifdef _MSC_VER +# define PSAPI_VERSION 2 +# define epicsEnumProcessModules K32EnumProcessModules +#else +# define epicsEnumProcessModules EnumProcessModules +#endif #include +#include #define epicsExportSharedSymbols +#include "epicsStdio.h" #include "epicsFindSymbol.h" -static int epicsLoadErrorCode = 0; +#ifdef _MSC_VER +# define STORE static __declspec( thread ) +#elif __GNUC__ +# define STORE static __thread +#else +# define STORE static +#endif + +STORE +DWORD epicsLoadErrorCode = 0; epicsShareFunc void * epicsLoadLibrary(const char *name) { @@ -19,28 +39,78 @@ epicsShareFunc void * epicsLoadLibrary(const char *name) epicsLoadErrorCode = 0; lib = LoadLibrary(name); - if (lib == NULL) - { - epicsLoadErrorCode = GetLastError(); - } + epicsLoadErrorCode = lib ? 0 : GetLastError(); return lib; } epicsShareFunc const char *epicsLoadError(void) { - static char buffer[100]; + STORE char buffer[100]; + DWORD n; - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM, + n = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, epicsLoadErrorCode, 0, buffer, sizeof(buffer)-1, NULL ); + + if(n) { + /* n - number of chars stored excluding nil. + * + * Some messages include a trailing newline, which we strip. + */ + for(; n>=1 && (buffer[n-1]=='\n' || buffer[n-1]=='\r'); n--) + buffer[n-1] = '\0'; + } else { + epicsSnprintf(buffer, sizeof(buffer), + "Unable to format WIN32 error code %lu", + (unsigned long)epicsLoadErrorCode); + buffer[sizeof(buffer)-1] = '\0'; + + } + return buffer; } epicsShareFunc void * epicsShareAPI epicsFindSymbol(const char *name) { - return GetProcAddress(0, name); + HANDLE proc = GetCurrentProcess(); + HMODULE *dlls=NULL; + DWORD nalloc=0u, needed=0u; + void* ret = NULL; + + /* As a handle returned by LoadLibrary() isn't available to us, + * try all loaded modules in arbitrary order. + */ + + if(!epicsEnumProcessModules(proc, NULL, 0, &needed)) { + epicsLoadErrorCode = GetLastError(); + return ret; + } + + if(!(dlls = malloc(nalloc = needed))) { + epicsLoadErrorCode = ERROR_NOT_ENOUGH_MEMORY; + return ret; + } + + if(epicsEnumProcessModules(proc, dlls, nalloc, &needed)) { + DWORD i, ndlls; + + /* settle potential races w/o retry by iterating smaller of nalloc or needed */ + if(nalloc > needed) + nalloc = needed; + + for(i=0, ndlls = nalloc/sizeof(*dlls); !ret && i + +#include + +#include "epicsUnitTest.h" +#include "testMain.h" + +#include "envDefs.h" +#include "epicsFindSymbol.h" +#include "epicsThread.h" + +namespace { + +void loadBad() +{ + testOk1(!epicsFindSymbol("noSuchFunction")); +} + +// lookup a symbol from libCom +// which this executable is linked against (maybe statically) +// Doesn't work for static builds on windows +void loadCom() +{ + testDiag("Lookup symbol from Com"); + +#if defined (_WIN32) && defined(LINKING_STATIC) + testTodoBegin("windows static build"); +#endif + + void* ptr = epicsFindSymbol("epicsThreadGetCPUs"); + testOk(ptr==(void*)&epicsThreadGetCPUs, + "%p == %p (epicsThreadGetCPUs) : %s", + ptr, (void*)&epicsThreadGetCPUs, + epicsLoadError()); + + testTodoEnd(); +} + +void loadCA() +{ + testDiag("Load and lookup symbol from libca"); + + std::string libname; + { + std::ostringstream strm; + // running in eg. modules/libcom/test/O.linux-x86_64-debug +#ifdef _WIN32 + strm<<"..\\..\\..\\..\\bin\\"<