VirtualBox

source: vbox/trunk/src/VBox/Main/cbinding/VBoxCAPIGlue.c

Last change on this file was 98694, checked in by vboxsync, 16 months ago

Main/cbindings,/Config.kmk: Added VBoxCAPI-x86.dll/so/dylib for 32-bit apps. bugref:7675

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
RevLine 
[55400]1/* $Id: VBoxCAPIGlue.c 98694 2023-02-22 23:08:43Z vboxsync $ */
[16832]2/** @file
[50183]3 * Glue code for dynamically linking to VBoxCAPI.
[16832]4 */
5
6/*
[98103]7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
[16832]8 *
[69377]9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
[16832]17 *
[69377]18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
[16837]20 *
[69377]21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
[18241]28 * OTHER DEALINGS IN THE SOFTWARE.
[16832]29 */
30
[57358]31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
[64448]35/* NOTE: do NOT use any include files here which are only available in the
36 * VirtualBox tree, e.g. iprt. They are not available in the SDK, which is
37 * where this file will provided as source code and has to be compilable. */
[50183]38#include "VBoxCAPIGlue.h"
39
[16832]40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
[19028]43#include <stdarg.h>
[64449]44#ifdef WIN32
45# define _INTPTR 2 /* on Windows stdint.h compares this in #if, causing warnings if not defined */
46#endif /* WIN32 */
[64448]47#include <stdint.h>
[50183]48#ifndef WIN32
49# include <dlfcn.h>
50# include <pthread.h>
[98694]51#else /* WIN32 */
[64448]52# include <Windows.h>
[50183]53#endif /* WIN32 */
[16832]54
55
[57358]56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
[98694]59#if defined(__i386__) || defined(_M_IX86) || defined(__X86__)
60/** This is a 32-bit process running against a 64-bit VBox installation.
61 * Since there are only 64-bit VBox now, we don't need any runtime checks. */
62# define IS_32_ON_64
63#endif
64
[18923]65#if defined(__linux__) || defined(__linux_gnu__) || defined(__sun__) || defined(__FreeBSD__)
[98694]66# ifndef IS_32_ON_64
67# define DYNLIB_NAME "VBoxXPCOMC.so"
68# else
69# define DYNLIB_NAME "VBoxCAPI-x86.so"
70# endif
[16832]71#elif defined(__APPLE__)
[98694]72# ifndef IS_32_ON_64
73# define DYNLIB_NAME "VBoxXPCOMC.dylib"
74# else
75# define DYNLIB_NAME "VBoxCAPI-x86.dylib"
76# endif
[50183]77#elif defined(WIN32)
[98694]78# ifndef IS_32_ON_64
79# define DYNLIB_NAME "VBoxCAPI.dll"
80# else
81# define DYNLIB_NAME "VBoxCAPI-x86.dll"
82# define DYNLIB_SUBDIR "x86"
83# define SLASH_DYNLIB_SUBDIR "\\" DYNLIB_SUBDIR
84# endif
[16832]85#else
86# error "Port me"
87#endif
[98694]88#ifndef DYNLIB_SUBDIR
89# define DYNLIB_SUBDIR ""
90# define SLASH_DYNLIB_SUBDIR ""
91#endif
[16832]92
[98694]93#ifdef WIN32
94# define DIR_SLASH_CH '\\'
95#else
96# define DIR_SLASH_CH '/'
97#endif
[18155]98
[98694]99
[57358]100/*********************************************************************************************************************************
101* Global Variables *
102*********************************************************************************************************************************/
[50183]103/** The so/dynsym/dll handle for VBoxCAPI. */
104#ifndef WIN32
105void *g_hVBoxCAPI = NULL;
106#else /* WIN32 */
107HMODULE g_hVBoxCAPI = NULL;
108#endif /* WIN32 */
[16832]109/** The last load error. */
[50183]110char g_szVBoxErrMsg[256] = "";
111/** Pointer to the VBOXCAPI function table. */
112PCVBOXCAPI g_pVBoxFuncs = NULL;
113/** Pointer to VBoxGetCAPIFunctions for the loaded VBoxCAPI so/dylib/dll. */
114PFNVBOXGETCAPIFUNCTIONS g_pfnGetFunctions = NULL;
[16832]115
[49539]116typedef void FNDUMMY(void);
117typedef FNDUMMY *PFNDUMMY;
118/** Just a dummy global structure containing a bunch of
[50183]119 * function pointers to code which is wanted in the link. */
120PFNDUMMY g_apfnVBoxCAPIGlue[] =
[49539]121{
[50183]122#ifndef WIN32
123 /* The following link dependency is for helping gdb as it gets hideously
124 * confused if the application doesn't drag in pthreads, but uses it. */
125 (PFNDUMMY)pthread_create,
126#endif /* !WIN32 */
127 NULL
[49539]128};
[16832]129
[49539]130
[16832]131/**
[19028]132 * Wrapper for setting g_szVBoxErrMsg. Can be an empty stub.
133 *
[19052]134 * @param fAlways When 0 the g_szVBoxErrMsg is only set if empty.
[19028]135 * @param pszFormat The format string.
136 * @param ... The arguments.
137 */
[19052]138static void setErrMsg(int fAlways, const char *pszFormat, ...)
[19028]139{
[19052]140 if ( fAlways
141 || !g_szVBoxErrMsg[0])
142 {
143 va_list va;
144 va_start(va, pszFormat);
145 vsnprintf(g_szVBoxErrMsg, sizeof(g_szVBoxErrMsg), pszFormat, va);
146 va_end(va);
147 }
[19028]148}
149
150
151/**
[50183]152 * Try load C API .so/dylib/dll from the specified location and resolve all
153 * the symbols we need. Tries both the new style and legacy name.
[16832]154 *
155 * @returns 0 on success, -1 on failure.
[50183]156 * @param pszHome The directory where to try load VBoxCAPI/VBoxXPCOMC
157 * from. Can be NULL.
[19028]158 * @param fSetAppHome Whether to set the VBOX_APP_HOME env.var. or not
159 * (boolean).
[16832]160 */
[98694]161static int tryLoadLibrary(const char *pszHome, const char *pszSub, int fSetAppHome)
[16832]162{
[98694]163 size_t const cchHome = pszHome ? strlen(pszHome) : 0;
164 size_t const cchSub = pszSub ? strlen(pszSub) : 0;
165 size_t cbBufNeeded;
166 size_t offName;
167 char szName[4096];
[16832]168
169 /*
170 * Construct the full name.
171 */
[98694]172 cbBufNeeded = cchHome + !!cchHome + cchSub + !!cchSub + sizeof(DYNLIB_NAME);
[19028]173 if (cbBufNeeded > sizeof(szName))
[16832]174 {
[19052]175 setErrMsg(1, "path buffer too small: %u bytes needed",
[19028]176 (unsigned)cbBufNeeded);
[16832]177 return -1;
178 }
[98694]179 offName = 0;
[18871]180 if (cchHome)
181 {
[98694]182 memcpy(&szName[offName], pszHome, cchHome);
183 offName += cchHome;
184 szName[offName++] = DIR_SLASH_CH;
[18871]185 }
[98694]186 if (cchSub)
187 {
188 memcpy(&szName[offName], pszSub, cchSub);
189 offName += cchSub;
190 szName[offName++] = DIR_SLASH_CH;
191 }
192 memcpy(&szName[offName], DYNLIB_NAME, sizeof(DYNLIB_NAME));
[16832]193
194 /*
195 * Try load it by that name, setting the VBOX_APP_HOME first (for now).
196 * Then resolve and call the function table getter.
197 */
[18871]198 if (fSetAppHome)
[18853]199 {
[50183]200#ifndef WIN32
[18871]201 if (pszHome)
202 setenv("VBOX_APP_HOME", pszHome, 1 /* always override */);
203 else
204 unsetenv("VBOX_APP_HOME");
[50183]205#endif /* !WIN32 */
[18853]206 }
[50183]207
208#ifndef WIN32
209 g_hVBoxCAPI = dlopen(szName, RTLD_NOW | RTLD_LOCAL);
[54027]210#else /* WIN32 */
[98694]211 g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */,
212 cchHome ? LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 : 0 /* dwFlags */);
213 if (!g_hVBoxCAPI && GetLastError() == ERROR_INVALID_PARAMETER)
214 g_hVBoxCAPI = LoadLibraryExA(szName, NULL /* hFile */, 0 /* dwFlags */);
[54027]215#endif /* WIN32 */
[50183]216 if (g_hVBoxCAPI)
[16832]217 {
[50183]218 PFNVBOXGETCAPIFUNCTIONS pfnGetFunctions;
[54027]219#ifndef WIN32
[50183]220 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t)
221 dlsym(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME);
[54027]222# ifdef VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME
[50183]223 if (!pfnGetFunctions)
224 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)(uintptr_t)
225 dlsym(g_hVBoxCAPI, VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME);
[54027]226# endif /* VBOX_GET_XPCOM_FUNCTIONS_SYMBOL_NAME */
227#else /* WIN32 */
228 pfnGetFunctions = (PFNVBOXGETCAPIFUNCTIONS)
229 GetProcAddress(g_hVBoxCAPI, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME);
230#endif /* WIN32 */
[16832]231 if (pfnGetFunctions)
232 {
[50183]233 g_pVBoxFuncs = pfnGetFunctions(VBOX_CAPI_VERSION);
[16832]234 if (g_pVBoxFuncs)
[17677]235 {
[98694]236 if ( VBOX_CAPI_MAJOR(g_pVBoxFuncs->uVersion)
237 == VBOX_CAPI_MAJOR(VBOX_CAPI_VERSION)
238 && VBOX_CAPI_MINOR(g_pVBoxFuncs->uVersion)
239 >= VBOX_CAPI_MINOR(VBOX_CAPI_VERSION))
[54027]240 {
241 g_pfnGetFunctions = pfnGetFunctions;
242 return 0;
243 }
244 setErrMsg(1, "%.80s: pfnGetFunctions(%#x) returned incompatible version %#x",
245 szName, VBOX_CAPI_VERSION, g_pVBoxFuncs->uVersion);
246 g_pVBoxFuncs = NULL;
[17677]247 }
[54027]248 else
249 {
250 /* bail out */
251 setErrMsg(1, "%.80s: pfnGetFunctions(%#x) failed",
252 szName, VBOX_CAPI_VERSION);
253 }
[16832]254 }
[19028]255 else
[54027]256 {
257#ifndef WIN32
[19052]258 setErrMsg(1, "dlsym(%.80s/%.32s): %.128s",
[50183]259 szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, dlerror());
[54027]260#else /* WIN32 */
[50183]261 setErrMsg(1, "GetProcAddress(%.80s/%.32s): %d",
262 szName, VBOX_GET_CAPI_FUNCTIONS_SYMBOL_NAME, GetLastError());
[54027]263#endif /* WIN32 */
264 }
265
266#ifndef WIN32
267 dlclose(g_hVBoxCAPI);
268#else /* WIN32 */
[50183]269 FreeLibrary(g_hVBoxCAPI);
[54027]270#endif /* WIN32 */
[50183]271 g_hVBoxCAPI = NULL;
272 }
273 else
[54027]274 {
275#ifndef WIN32
276 setErrMsg(0, "dlopen(%.80s): %.160s", szName, dlerror());
277#else /* WIN32 */
[50183]278 setErrMsg(0, "LoadLibraryEx(%.80s): %d", szName, GetLastError());
[54027]279#endif /* WIN32 */
280 }
[50183]281
282 return -1;
[16832]283}
284
285
286/**
[50183]287 * Tries to locate and load VBoxCAPI.so/dylib/dll, resolving all the related
[16832]288 * function pointers.
289 *
290 * @returns 0 on success, -1 on failure.
291 *
292 * @remark This should be considered moved into a separate glue library since
[50183]293 * its its going to be pretty much the same for any user of VBoxCAPI
[16832]294 * and it will just cause trouble to have duplicate versions of this
295 * source code all around the place.
296 */
[17813]297int VBoxCGlueInit(void)
[16832]298{
[50183]299 const char *pszHome;
300
301 memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg));
302
[16832]303 /*
304 * If the user specifies the location, try only that.
305 */
[50183]306 pszHome = getenv("VBOX_APP_HOME");
[16832]307 if (pszHome)
[98694]308 return tryLoadLibrary(pszHome, DYNLIB_SUBDIR, 0);
[16832]309
310 /*
311 * Try the known standard locations.
312 */
313#if defined(__gnu__linux__) || defined(__linux__)
[98694]314 if (tryLoadLibrary("/opt/VirtualBox", DYNLIB_SUBDIR, 1) == 0)
[16832]315 return 0;
[98694]316 if (tryLoadLibrary("/usr/lib/virtualbox", DYNLIB_SUBDIR, 1) == 0)
[16832]317 return 0;
318#elif defined(__sun__)
[98694]319 if (tryLoadLibrary("/opt/VirtualBox/amd64", NULL, 1) == 0)
[16832]320 return 0;
[98694]321 if (tryLoadLibrary("/opt/VirtualBox/i386", NULL, 1) == 0)
[16832]322 return 0;
323#elif defined(__APPLE__)
[98694]324 if (tryLoadLibrary("/Applications/VirtualBox.app/Contents/MacOS", DYNLIB_SUBDIR, 1) == 0)
[16832]325 return 0;
[18923]326#elif defined(__FreeBSD__)
[98694]327 if (tryLoadLibrary("/usr/local/lib/virtualbox", DYNLIB_SUBDIR, 1) == 0)
[18923]328 return 0;
[98694]329#elif defined(WIN32)
330# ifdef IS_32_ON_64
331 pszHome = getenv("ProgramW6432");
332 if (pszHome && tryLoadLibrary(pszHome, "\\Oracle\\VirtualBox" SLASH_DYNLIB_SUBDIR, 1) == 0)
[33396]333 return 0;
[98694]334# endif
[50183]335 pszHome = getenv("ProgramFiles");
[98694]336 if (pszHome && tryLoadLibrary(pszHome, "\\Oracle\\VirtualBox" SLASH_DYNLIB_SUBDIR, 1) == 0)
[50183]337 return 0;
[98694]338 if (tryLoadLibrary("C:\\Program Files\\Oracle\\VirtualBox", DYNLIB_SUBDIR, 1) == 0)
339 return 0;
[16832]340#else
341# error "port me"
342#endif
343
344 /*
345 * Finally try the dynamic linker search path.
346 */
[98694]347 if (tryLoadLibrary(NULL, NULL, 1) == 0)
[16832]348 return 0;
349
350 /* No luck, return failure. */
351 return -1;
352}
353
[18155]354
[16832]355/**
356 * Terminate the C glue library.
357 */
358void VBoxCGlueTerm(void)
359{
[50183]360 if (g_hVBoxCAPI)
[17570]361 {
[18156]362#if 0 /* VBoxRT.so doesn't like being reloaded. See @bugref{3725}. */
[50183]363#ifndef WIN32
364 dlclose(g_hVBoxCAPI);
365#else
366 FreeLibrary(g_hVBoxCAPI);
[18156]367#endif
[50183]368#endif
369 g_hVBoxCAPI = NULL;
[17570]370 }
371 g_pVBoxFuncs = NULL;
[17677]372 g_pfnGetFunctions = NULL;
[19028]373 memset(g_szVBoxErrMsg, 0, sizeof(g_szVBoxErrMsg));
[16832]374}
[18155]375
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use