blob: 3216cd1a8e1b774548be7bec89a1c1010bb762a0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CDEV_CURRENT_FUNCTION _comment_
/**
* @file
* @ingroup Port
* @brief shared library
*/
#undef CDEV_CURRENT_FUNCTION
#include <windows.h>
#include "hyport.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "portnls.h"
#if !defined(HINSTANCE_ERROR)
#define HINSTANCE_ERROR 32
#endif
#define CDEV_CURRENT_FUNCTION _prototypes_private
UDATA VMCALL EsSharedLibraryLookupName (UDATA descriptor, const char *name,
UDATA * func);
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION EsSharedLibraryLookupName
UDATA VMCALL
EsSharedLibraryLookupName (UDATA descriptor, const char *name, UDATA * func)
{
UDATA lpfnFunction;
if (descriptor < HINSTANCE_ERROR)
{
return 3;
}
lpfnFunction =
(UDATA) GetProcAddress ((HINSTANCE) descriptor, (LPCSTR) name);
if (lpfnFunction == (UDATA) NULL)
{
return 4;
}
*func = lpfnFunction;
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hysl_open_shared_library
/**
* Opens a shared library.
*
* @param[in] portLibrary The port library.
* @param[in] name path Null-terminated string containing the shared library.
* @param[out] descriptor Pointer to memory which is filled in with shared-library handle on success.
* @param[in] decorate Boolean value indicates whether name should be decorated
* if it contains path information and cannot be found.
*
* @return 0 on success, any other value on failure.
*
* @note contents of descriptor are undefined on failure.
*/
UDATA VMCALL
hysl_open_shared_library (struct HyPortLibrary * portLibrary, char *name,
UDATA * descriptor, BOOLEAN decorate)
{
HINSTANCE dllHandle;
UINT prevMode;
DWORD error;
UDATA notFound;
const char *errorMessage;
char errBuf[512];
char mangledName[1024];
char *openName = name;
if (decorate)
{
portLibrary->str_printf (portLibrary, mangledName, 1024, "%s.dll",
name);
openName = mangledName;
} /* TODO make windows not try to append .dll if we do not want it to */
prevMode = SetErrorMode (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
/* LoadLibrary will try appending .DLL if necessary */
dllHandle = LoadLibrary ((LPCSTR) openName);
if (dllHandle >= (HINSTANCE) HINSTANCE_ERROR)
{
*descriptor = (UDATA) dllHandle;
SetErrorMode (prevMode);
return 0;
}
error = GetLastError ();
notFound = (error == ERROR_MOD_NOT_FOUND || error == ERROR_DLL_NOT_FOUND);
if (notFound)
{
/* try to report a better error message. Check if the library can be found at all. */
dllHandle =
LoadLibraryEx ((LPCSTR) openName, NULL, DONT_RESOLVE_DLL_REFERENCES);
if (dllHandle)
{
if (sizeof (errBuf))
{
errorMessage = portLibrary->nls_lookup_message (portLibrary,
HYNLS_ERROR |
HYNLS_DO_NOT_APPEND_NEWLINE,
HYNLS_PORT_SL_UNABLE_TO_RESOLVE_REFERENCES,
NULL);
strncpy (errBuf, errorMessage, sizeof (errBuf));
errBuf[sizeof (errBuf) - 1] = '\0';
}
FreeLibrary (dllHandle);
SetErrorMode (prevMode);
return portLibrary->error_set_last_error_with_message (portLibrary,
HYPORT_SL_INVALID,
errBuf);
}
}
if (sizeof (errBuf))
{
LPWSTR message = NULL;
int nameSize = strlen (name);
LPWSTR filename =
(LPWSTR) portLibrary->mem_allocate_memory (portLibrary,
nameSize * 2 + 2);
if (filename == NULL)
{
errorMessage = portLibrary->nls_lookup_message (portLibrary,
HYNLS_ERROR |
HYNLS_DO_NOT_APPEND_NEWLINE,
HYNLS_PORT_SL_INTERNAL_ERROR,
NULL);
portLibrary->str_printf (portLibrary, errBuf, sizeof (errBuf),
errorMessage, error);
errBuf[sizeof (errBuf) - 1] = '\0';
SetErrorMode (prevMode);
return portLibrary->error_set_last_error_with_message (portLibrary,
notFound ?
HYPORT_SL_NOT_FOUND
:
HYPORT_SL_INVALID,
errBuf);
}
MultiByteToWideChar (CP_ACP, 0, (LPCTSTR) name, -1, filename,
nameSize * 2 + 2);
filename[nameSize] = '\0';
FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, error, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(LPWSTR) & message, 0, (va_list *) & filename);
portLibrary->mem_free_memory (portLibrary, filename);
if (message)
{
WideCharToMultiByte (CP_UTF8, 0, (LPCWSTR) message, -1, errBuf,
sizeof (errBuf) - 1, NULL, NULL);
LocalFree (message);
}
else
{
errorMessage = portLibrary->nls_lookup_message (portLibrary,
HYNLS_ERROR |
HYNLS_DO_NOT_APPEND_NEWLINE,
HYNLS_PORT_SL_INTERNAL_ERROR,
NULL);
portLibrary->str_printf (portLibrary, errBuf, sizeof (errBuf),
errorMessage, error);
}
errBuf[sizeof (errBuf) - 1] = '\0';
}
SetErrorMode (prevMode);
return portLibrary->error_set_last_error_with_message (portLibrary,
notFound ?
HYPORT_SL_NOT_FOUND :
HYPORT_SL_INVALID,
errBuf);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hysl_close_shared_library
/**
* Close a shared library.
*
* @param[in] portLibrary The port library.
* @param[in] descriptor Shared library handle to close.
*
* @return 0 on success, any other value on failure.
*/
UDATA VMCALL
hysl_close_shared_library (struct HyPortLibrary * portLibrary,
UDATA descriptor)
{
if (descriptor < HINSTANCE_ERROR)
{
return 2;
}
FreeLibrary ((HINSTANCE) descriptor);
return 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hysl_lookup_name
/**
* Search for a function named 'name' taking argCount in the shared library 'descriptor'.
*
* @param[in] portLibrary The port library.
* @param[in] descriptor Shared library to search.
* @param[in] name Function to look up.
* @param[out] func Pointer to the function.
* @param[in] argSignature Argument signature.
*
* @return 0 on success, any other value on failure.
*
* argSignature is a C (ie: NUL-terminated) string with the following possible values for each character:
*
* V - void
* Z - boolean
* B - byte
* C - char (16 bits)
* I - integer (32 bits)
* J - long (64 bits)
* F - float (32 bits)
* D - double (64 bits)
* L - object / pointer (32 or 64, depending on platform)
* P - pointer-width platform data. (in this context an IDATA)
*
* Lower case signature characters imply unsigned value.
* Upper case signature characters imply signed values.
* If it doesn't make sense to be signed/unsigned (eg: V, L, F, D Z) the character is upper case.
*
* argList[0] is the return type from the function.
* The argument list is as it appears in english: list is left (1) to right (argCount)
*
* @note contents of func are undefined on failure.
*/
UDATA VMCALL
hysl_lookup_name (struct HyPortLibrary * portLibrary, UDATA descriptor,
const char *name, UDATA * func, const char *argSignature)
{
char *mangledName;
UDATA result;
result = EsSharedLibraryLookupName (descriptor, name, func);
if (result != 0)
{
int i, len, pad = 0;
/* + 7 comes from: 256 parameters * 8 bytes each = 2048 bytes -> 4 digits + @ symbol + leading '_' + NULL */
size_t length = sizeof (char) * (strlen (name) + 7);
if (!(mangledName = (char *) alloca (length)))
{
return 1;
}
len = strlen (argSignature);
for (i = 1; i < len; i++)
{
if (argSignature[i] == 'J' || argSignature[i] == 'D')
{
pad++;
}
}
portLibrary->str_printf (portLibrary, mangledName, length, "_%s@%d",
name, (len + pad - 1) * 4);
result = EsSharedLibraryLookupName (descriptor, mangledName, func);
}
return result;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hysl_shutdown
/**
* PortLibrary shutdown.
*
* This function is called during shutdown of the portLibrary. Any resources that were created by @ref hysl_startup
* should be destroyed here.
*
* @param[in] portLibrary The port library.
*
* @note Most implementations will be empty.
*/
void VMCALL
hysl_shutdown (struct HyPortLibrary *portLibrary)
{
/* empty */
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hysl_startup
/**
* PortLibrary startup.
*
* This function is called during startup of the portLibrary. Any resources that are required for
* the shared library operations may be created here. All resources created here should be destroyed
* in @ref hysl_shutdown.
*
* @param[in] portLibrary The port library.
*
* @return 0 on success, negative error code on failure. Error code values returned are
* \arg HYPORT_ERROR_STARTUP_SL
*
* @note Most implementations will simply return success.
*/
I_32 VMCALL
hysl_startup (struct HyPortLibrary *portLibrary)
{
return 0;
}
#undef CDEV_CURRENT_FUNCTION