summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/library
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:24:41 +0000
commita9bcc81f821d7c66f623779fa5147e728eb3c388 (patch)
tree98676963bcdd537ae5908a067a8eb110b93486a6 /winpr/libwinpr/library
parentInitial commit. (diff)
downloadfreerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz
freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'winpr/libwinpr/library')
-rw-r--r--winpr/libwinpr/library/CMakeLists.txt22
-rw-r--r--winpr/libwinpr/library/ModuleOptions.cmake9
-rw-r--r--winpr/libwinpr/library/library.c381
-rw-r--r--winpr/libwinpr/library/test/CMakeLists.txt33
-rw-r--r--winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt29
-rw-r--r--winpr/libwinpr/library/test/TestLibraryA/TestLibraryA.c14
-rw-r--r--winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt30
-rw-r--r--winpr/libwinpr/library/test/TestLibraryB/TestLibraryB.c14
-rw-r--r--winpr/libwinpr/library/test/TestLibraryGetModuleFileName.c56
-rw-r--r--winpr/libwinpr/library/test/TestLibraryGetProcAddress.c89
-rw-r--r--winpr/libwinpr/library/test/TestLibraryLoadLibrary.c51
11 files changed, 728 insertions, 0 deletions
diff --git a/winpr/libwinpr/library/CMakeLists.txt b/winpr/libwinpr/library/CMakeLists.txt
new file mode 100644
index 0000000..9db7d0d
--- /dev/null
+++ b/winpr/libwinpr/library/CMakeLists.txt
@@ -0,0 +1,22 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-library cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed 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.
+
+winpr_module_add(library.c)
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/winpr/libwinpr/library/ModuleOptions.cmake b/winpr/libwinpr/library/ModuleOptions.cmake
new file mode 100644
index 0000000..affda86
--- /dev/null
+++ b/winpr/libwinpr/library/ModuleOptions.cmake
@@ -0,0 +1,9 @@
+
+set(MINWIN_LAYER "1")
+set(MINWIN_GROUP "core")
+set(MINWIN_MAJOR_VERSION "1")
+set(MINWIN_MINOR_VERSION "1")
+set(MINWIN_SHORT_NAME "libraryloader")
+set(MINWIN_LONG_NAME "Dynamic-Link Library Functions")
+set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}")
+
diff --git a/winpr/libwinpr/library/library.c b/winpr/libwinpr/library/library.c
new file mode 100644
index 0000000..307dc20
--- /dev/null
+++ b/winpr/libwinpr/library/library.c
@@ -0,0 +1,381 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Library Loader
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed 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.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/crt.h>
+#include <winpr/platform.h>
+
+#include <winpr/library.h>
+
+#include "../log.h"
+#define TAG WINPR_TAG("library")
+
+/**
+ * api-ms-win-core-libraryloader-l1-1-1.dll:
+ *
+ * AddDllDirectory
+ * RemoveDllDirectory
+ * SetDefaultDllDirectories
+ * DisableThreadLibraryCalls
+ * EnumResourceLanguagesExA
+ * EnumResourceLanguagesExW
+ * EnumResourceNamesExA
+ * EnumResourceNamesExW
+ * EnumResourceTypesExA
+ * EnumResourceTypesExW
+ * FindResourceExW
+ * FindStringOrdinal
+ * FreeLibrary
+ * FreeLibraryAndExitThread
+ * FreeResource
+ * GetModuleFileNameA
+ * GetModuleFileNameW
+ * GetModuleHandleA
+ * GetModuleHandleExA
+ * GetModuleHandleExW
+ * GetModuleHandleW
+ * GetProcAddress
+ * LoadLibraryExA
+ * LoadLibraryExW
+ * LoadResource
+ * LoadStringA
+ * LoadStringW
+ * LockResource
+ * QueryOptionalDelayLoadedAPI
+ * SizeofResource
+ */
+
+#if !defined(_WIN32) || defined(_UWP)
+
+#ifndef _WIN32
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __MACOSX__
+#include <mach-o/dyld.h>
+#endif
+
+#endif
+
+DLL_DIRECTORY_COOKIE AddDllDirectory(PCWSTR NewDirectory)
+{
+ /* TODO: Implement */
+ WLog_ERR(TAG, "not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return NULL;
+}
+
+BOOL RemoveDllDirectory(DLL_DIRECTORY_COOKIE Cookie)
+{
+ /* TODO: Implement */
+ WLog_ERR(TAG, "not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+BOOL SetDefaultDllDirectories(DWORD DirectoryFlags)
+{
+ /* TODO: Implement */
+ WLog_ERR(TAG, "not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE;
+}
+
+HMODULE LoadLibraryA(LPCSTR lpLibFileName)
+{
+#if defined(_UWP)
+ int status;
+ HMODULE hModule = NULL;
+ WCHAR* filenameW = NULL;
+
+ if (!lpLibFileName)
+ return NULL;
+
+ filenameW = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
+ if (filenameW)
+ return NULL;
+
+ hModule = LoadLibraryW(filenameW);
+ free(filenameW);
+ return hModule;
+#else
+ HMODULE library = NULL;
+ library = dlopen(lpLibFileName, RTLD_LOCAL | RTLD_LAZY);
+
+ if (!library)
+ {
+ const char* err = dlerror();
+ WLog_ERR(TAG, "failed with %s", err);
+ return NULL;
+ }
+
+ return library;
+#endif
+}
+
+HMODULE LoadLibraryW(LPCWSTR lpLibFileName)
+{
+ if (!lpLibFileName)
+ return NULL;
+#if defined(_UWP)
+ return LoadPackagedLibrary(lpLibFileName, 0);
+#else
+ HMODULE module = NULL;
+ char* name = ConvertWCharToUtf8Alloc(lpLibFileName, NULL);
+ if (!name)
+ return NULL;
+
+ module = LoadLibraryA(name);
+ free(name);
+ return module;
+#endif
+}
+
+HMODULE LoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ if (dwFlags != 0)
+ WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
+
+ if (hFile)
+ WLog_WARN(TAG, "does not support hFile != NULL");
+
+ return LoadLibraryA(lpLibFileName);
+}
+
+HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ if (dwFlags != 0)
+ WLog_WARN(TAG, "does not support dwFlags 0x%08" PRIx32, dwFlags);
+
+ if (hFile)
+ WLog_WARN(TAG, "does not support hFile != NULL");
+
+ return LoadLibraryW(lpLibFileName);
+}
+
+#endif
+
+#if !defined(_WIN32) && !defined(__CYGWIN__)
+
+FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName)
+{
+ FARPROC proc = NULL;
+ proc = dlsym(hModule, lpProcName);
+
+ if (proc == NULL)
+ {
+ WLog_ERR(TAG, "GetProcAddress: could not find procedure %s: %s", lpProcName, dlerror());
+ return (FARPROC)NULL;
+ }
+
+ return proc;
+}
+
+BOOL FreeLibrary(HMODULE hLibModule)
+{
+ int status = 0;
+ status = dlclose(hLibModule);
+
+ if (status != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+HMODULE GetModuleHandleA(LPCSTR lpModuleName)
+{
+ /* TODO: Implement */
+ WLog_ERR(TAG, "not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return NULL;
+}
+
+HMODULE GetModuleHandleW(LPCWSTR lpModuleName)
+{
+ /* TODO: Implement */
+ WLog_ERR(TAG, "not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return NULL;
+}
+
+/**
+ * GetModuleFileName:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms683197/
+ *
+ * Finding current executable's path without /proc/self/exe:
+ * http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
+ */
+
+DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize)
+{
+ DWORD status = 0;
+ if (!lpFilename)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+
+ char* name = calloc(nSize, sizeof(char));
+ if (!name)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+ status = GetModuleFileNameA(hModule, name, nSize);
+
+ if ((status > INT_MAX) || (nSize > INT_MAX))
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ status = 0;
+ }
+
+ if (status > 0)
+ {
+ if (ConvertUtf8NToWChar(name, status, lpFilename, nSize) < 0)
+ {
+ free(name);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+
+ free(name);
+ return status;
+}
+
+DWORD GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
+{
+#if defined(__linux__)
+ SSIZE_T status = 0;
+ size_t length = 0;
+ char path[64];
+
+ if (!hModule)
+ {
+ char buffer[4096];
+ sprintf_s(path, ARRAYSIZE(path), "/proc/%d/exe", getpid());
+ status = readlink(path, buffer, sizeof(buffer));
+
+ if (status < 0)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+
+ buffer[status] = '\0';
+ length = strnlen(buffer, sizeof(buffer));
+
+ if (length < nSize)
+ {
+ CopyMemory(lpFilename, buffer, length);
+ lpFilename[length] = '\0';
+ return (DWORD)length;
+ }
+
+ CopyMemory(lpFilename, buffer, nSize - 1);
+ lpFilename[nSize - 1] = '\0';
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return nSize;
+ }
+
+#elif defined(__MACOSX__)
+ int status;
+ size_t length;
+
+ if (!hModule)
+ {
+ char path[4096];
+ char buffer[4096];
+ uint32_t size = sizeof(path);
+ status = _NSGetExecutablePath(path, &size);
+
+ if (status != 0)
+ {
+ /* path too small */
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /*
+ * _NSGetExecutablePath may not return the canonical path,
+ * so use realpath to find the absolute, canonical path.
+ */
+ realpath(path, buffer);
+ length = strnlen(buffer, sizeof(buffer));
+
+ if (length < nSize)
+ {
+ CopyMemory(lpFilename, buffer, length);
+ lpFilename[length] = '\0';
+ return (DWORD)length;
+ }
+
+ CopyMemory(lpFilename, buffer, nSize - 1);
+ lpFilename[nSize - 1] = '\0';
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return nSize;
+ }
+
+#endif
+ WLog_ERR(TAG, "is not implemented");
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+#endif
+
+HMODULE LoadLibraryX(LPCSTR lpLibFileName)
+{
+ if (!lpLibFileName)
+ return NULL;
+
+#if defined(_WIN32)
+ HMODULE hm = NULL;
+ WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
+
+ if (wstr)
+ hm = LoadLibraryW(wstr);
+ free(wstr);
+ return hm;
+#else
+ return LoadLibraryA(lpLibFileName);
+#endif
+}
+
+HMODULE LoadLibraryExX(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ if (!lpLibFileName)
+ return NULL;
+#if defined(_WIN32)
+ HMODULE hm = NULL;
+ WCHAR* wstr = ConvertUtf8ToWCharAlloc(lpLibFileName, NULL);
+ if (wstr)
+ hm = LoadLibraryExW(wstr, hFile, dwFlags);
+ free(wstr);
+ return hm;
+#else
+ return LoadLibraryExA(lpLibFileName, hFile, dwFlags);
+#endif
+}
diff --git a/winpr/libwinpr/library/test/CMakeLists.txt b/winpr/libwinpr/library/test/CMakeLists.txt
new file mode 100644
index 0000000..dca2b25
--- /dev/null
+++ b/winpr/libwinpr/library/test/CMakeLists.txt
@@ -0,0 +1,33 @@
+
+set(MODULE_NAME "TestLibrary")
+set(MODULE_PREFIX "TEST_LIBRARY")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestLibraryLoadLibrary.c
+ TestLibraryGetProcAddress.c
+ TestLibraryGetModuleFileName.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+target_link_libraries(${MODULE_NAME} winpr)
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+set(TEST_AREA "${MODULE_NAME}Area")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
+
+add_subdirectory(TestLibraryA)
+add_subdirectory(TestLibraryB)
+
diff --git a/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt b/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt
new file mode 100644
index 0000000..73d8b7e
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryA/CMakeLists.txt
@@ -0,0 +1,29 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-library cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed 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.
+
+set(MODULE_NAME "TestLibraryA")
+set(MODULE_PREFIX "TEST_LIBRARY_A")
+
+set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} TestLibraryA.c)
+
+add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
+
+set_target_properties(${MODULE_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test/Extra")
diff --git a/winpr/libwinpr/library/test/TestLibraryA/TestLibraryA.c b/winpr/libwinpr/library/test/TestLibraryA/TestLibraryA.c
new file mode 100644
index 0000000..d11bc4d
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryA/TestLibraryA.c
@@ -0,0 +1,14 @@
+#include <winpr/spec.h>
+
+DECLSPEC_EXPORT int FunctionA(int a, int b);
+DECLSPEC_EXPORT int FunctionB(int a, int b);
+
+int FunctionA(int a, int b)
+{
+ return (a * b); /* multiply */
+}
+
+int FunctionB(int a, int b)
+{
+ return (a / b); /* divide */
+}
diff --git a/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt b/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt
new file mode 100644
index 0000000..860df8c
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryB/CMakeLists.txt
@@ -0,0 +1,30 @@
+# WinPR: Windows Portable Runtime
+# libwinpr-library cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed 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.
+
+set(MODULE_NAME "TestLibraryB")
+set(MODULE_PREFIX "TEST_LIBRARY_B")
+
+set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} TestLibraryB.c)
+
+add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
+
+set_target_properties(${MODULE_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test/Extra")
+
diff --git a/winpr/libwinpr/library/test/TestLibraryB/TestLibraryB.c b/winpr/libwinpr/library/test/TestLibraryB/TestLibraryB.c
new file mode 100644
index 0000000..eac586e
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryB/TestLibraryB.c
@@ -0,0 +1,14 @@
+#include <winpr/spec.h>
+
+DECLSPEC_EXPORT int FunctionA(int a, int b);
+DECLSPEC_EXPORT int FunctionB(int a, int b);
+
+int FunctionA(int a, int b)
+{
+ return (a + b); /* add */
+}
+
+int FunctionB(int a, int b)
+{
+ return (a - b); /* subtract */
+}
diff --git a/winpr/libwinpr/library/test/TestLibraryGetModuleFileName.c b/winpr/libwinpr/library/test/TestLibraryGetModuleFileName.c
new file mode 100644
index 0000000..714522a
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryGetModuleFileName.c
@@ -0,0 +1,56 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/path.h>
+#include <winpr/tchar.h>
+#include <winpr/windows.h>
+#include <winpr/library.h>
+
+int TestLibraryGetModuleFileName(int argc, char* argv[])
+{
+ char ModuleFileName[4096];
+ DWORD len = 0;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ /* Test insufficient buffer size behaviour */
+ SetLastError(ERROR_SUCCESS);
+ len = GetModuleFileNameA(NULL, ModuleFileName, 2);
+ if (len != 2)
+ {
+ printf("%s: GetModuleFileNameA unexpectedly returned %" PRIu32 " instead of 2\n", __func__,
+ len);
+ return -1;
+ }
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ printf("%s: Invalid last error value: 0x%08" PRIX32
+ ". Expected 0x%08X (ERROR_INSUFFICIENT_BUFFER)\n",
+ __func__, GetLastError(), ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+
+ /* Test with real/sufficient buffer size */
+ SetLastError(ERROR_SUCCESS);
+ len = GetModuleFileNameA(NULL, ModuleFileName, sizeof(ModuleFileName));
+ if (len == 0)
+ {
+ printf("%s: GetModuleFileNameA failed with error 0x%08" PRIX32 "\n", __func__,
+ GetLastError());
+ return -1;
+ }
+ if (len == sizeof(ModuleFileName))
+ {
+ printf("%s: GetModuleFileNameA unexpectedly returned nSize\n", __func__);
+ return -1;
+ }
+ if (GetLastError() != ERROR_SUCCESS)
+ {
+ printf("%s: Invalid last error value: 0x%08" PRIX32 ". Expected 0x%08X (ERROR_SUCCESS)\n",
+ __func__, GetLastError(), ERROR_SUCCESS);
+ return -1;
+ }
+
+ printf("GetModuleFileNameA: %s\n", ModuleFileName);
+
+ return 0;
+}
diff --git a/winpr/libwinpr/library/test/TestLibraryGetProcAddress.c b/winpr/libwinpr/library/test/TestLibraryGetProcAddress.c
new file mode 100644
index 0000000..f8f54a6
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryGetProcAddress.c
@@ -0,0 +1,89 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/path.h>
+#include <winpr/tchar.h>
+#include <winpr/windows.h>
+#include <winpr/library.h>
+
+typedef int (*TEST_AB_FN)(int a, int b);
+
+int TestLibraryGetProcAddress(int argc, char* argv[])
+{
+ int a = 0;
+ int b = 0;
+ int c = 0;
+ HINSTANCE library = NULL;
+ TEST_AB_FN pFunctionA = NULL;
+ TEST_AB_FN pFunctionB = NULL;
+ LPCSTR SharedLibraryExtension = NULL;
+ CHAR LibraryPath[PATHCCH_MAX_CCH];
+ PCHAR p = NULL;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ if (!GetModuleFileNameA(NULL, LibraryPath, PATHCCH_MAX_CCH))
+ {
+ printf("%s: GetModuleFilenameA failed: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ /* PathCchRemoveFileSpec is not implemented in WinPR */
+
+ if (!(p = strrchr(LibraryPath, PathGetSeparatorA(PATH_STYLE_NATIVE))))
+ {
+ printf("%s: Error identifying module directory path\n", __func__);
+ return -1;
+ }
+
+ *p = 0;
+ NativePathCchAppendA(LibraryPath, PATHCCH_MAX_CCH, "TestLibraryA");
+ SharedLibraryExtension = PathGetSharedLibraryExtensionA(PATH_SHARED_LIB_EXT_WITH_DOT);
+ NativePathCchAddExtensionA(LibraryPath, PATHCCH_MAX_CCH, SharedLibraryExtension);
+ printf("%s: Loading Library: '%s'\n", __func__, LibraryPath);
+
+ if (!(library = LoadLibraryA(LibraryPath)))
+ {
+ printf("%s: LoadLibraryA failure: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ if (!(pFunctionA = (TEST_AB_FN)GetProcAddress(library, "FunctionA")))
+ {
+ printf("%s: GetProcAddress failure (FunctionA)\n", __func__);
+ return -1;
+ }
+
+ if (!(pFunctionB = (TEST_AB_FN)GetProcAddress(library, "FunctionB")))
+ {
+ printf("%s: GetProcAddress failure (FunctionB)\n", __func__);
+ return -1;
+ }
+
+ a = 2;
+ b = 3;
+ c = pFunctionA(a, b); /* LibraryA / FunctionA multiplies a and b */
+
+ if (c != (a * b))
+ {
+ printf("%s: pFunctionA call failed\n", __func__);
+ return -1;
+ }
+
+ a = 10;
+ b = 5;
+ c = pFunctionB(a, b); /* LibraryA / FunctionB divides a by b */
+
+ if (c != (a / b))
+ {
+ printf("%s: pFunctionB call failed\n", __func__);
+ return -1;
+ }
+
+ if (!FreeLibrary(library))
+ {
+ printf("%s: FreeLibrary failure: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/winpr/libwinpr/library/test/TestLibraryLoadLibrary.c b/winpr/libwinpr/library/test/TestLibraryLoadLibrary.c
new file mode 100644
index 0000000..4bd6e7c
--- /dev/null
+++ b/winpr/libwinpr/library/test/TestLibraryLoadLibrary.c
@@ -0,0 +1,51 @@
+
+#include <stdio.h>
+#include <winpr/crt.h>
+#include <winpr/path.h>
+#include <winpr/tchar.h>
+#include <winpr/windows.h>
+#include <winpr/library.h>
+
+int TestLibraryLoadLibrary(int argc, char* argv[])
+{
+ HINSTANCE library = NULL;
+ LPCSTR SharedLibraryExtension = NULL;
+ CHAR LibraryPath[PATHCCH_MAX_CCH];
+ PCHAR p = NULL;
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+ if (!GetModuleFileNameA(NULL, LibraryPath, PATHCCH_MAX_CCH))
+ {
+ printf("%s: GetModuleFilenameA failed: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ /* PathCchRemoveFileSpec is not implemented in WinPR */
+
+ if (!(p = strrchr(LibraryPath, PathGetSeparatorA(PATH_STYLE_NATIVE))))
+ {
+ printf("%s: Error identifying module directory path\n", __func__);
+ return -1;
+ }
+ *p = 0;
+
+ NativePathCchAppendA(LibraryPath, PATHCCH_MAX_CCH, "TestLibraryA");
+ SharedLibraryExtension = PathGetSharedLibraryExtensionA(PATH_SHARED_LIB_EXT_WITH_DOT);
+ NativePathCchAddExtensionA(LibraryPath, PATHCCH_MAX_CCH, SharedLibraryExtension);
+
+ printf("%s: Loading Library: '%s'\n", __func__, LibraryPath);
+
+ if (!(library = LoadLibraryA(LibraryPath)))
+ {
+ printf("%s: LoadLibraryA failure: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ if (!FreeLibrary(library))
+ {
+ printf("%s: FreeLibrary failure: 0x%08" PRIX32 "\n", __func__, GetLastError());
+ return -1;
+ }
+
+ return 0;
+}