Collection of DPF-based plugins for packaging
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
13KB

  1. /*
  2. * dlfcn-win32
  3. * Copyright (c) 2007 Ramiro Polla
  4. * Copyright (c) 2015 Tiancheng "Timothy" Gu
  5. *
  6. * dlfcn-win32 is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * dlfcn-win32 is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with dlfcn-win32; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #ifdef _DEBUG
  21. #define _CRTDBG_MAP_ALLOC
  22. #include <stdlib.h>
  23. #include <crtdbg.h>
  24. #endif
  25. #define PSAPI_VERSION 1
  26. #include <windows.h>
  27. #include <psapi.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef SHARED
  31. #define DLFCN_WIN32_EXPORTS
  32. #endif
  33. #include "dlfcn.h"
  34. #if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) )
  35. #define snprintf sprintf_s
  36. #endif
  37. #ifdef UNICODE
  38. #include <wchar.h>
  39. #define CHAR wchar_t
  40. #define UNICODE_L(s) L##s
  41. #else
  42. #define CHAR char
  43. #define UNICODE_L(s) s
  44. #endif
  45. /* Note:
  46. * MSDN says these functions are not thread-safe. We make no efforts to have
  47. * any kind of thread safety.
  48. */
  49. typedef struct global_object {
  50. HMODULE hModule;
  51. struct global_object *previous;
  52. struct global_object *next;
  53. } global_object;
  54. static global_object first_object;
  55. static global_object first_automatic_object;
  56. static int auto_ref_count = 0;
  57. /* These functions implement a double linked list for the global objects. */
  58. static global_object *global_search( global_object *start, HMODULE hModule )
  59. {
  60. global_object *pobject;
  61. if( hModule == NULL )
  62. return NULL;
  63. for( pobject = start; pobject; pobject = pobject->next )
  64. if( pobject->hModule == hModule )
  65. return pobject;
  66. return NULL;
  67. }
  68. static void global_add( global_object *start, HMODULE hModule )
  69. {
  70. global_object *pobject;
  71. global_object *nobject;
  72. if( hModule == NULL )
  73. return;
  74. pobject = global_search( start, hModule );
  75. /* Do not add object again if it's already on the list */
  76. if( pobject )
  77. return;
  78. if( start == &first_automatic_object )
  79. {
  80. pobject = global_search( &first_object, hModule );
  81. if( pobject )
  82. return;
  83. }
  84. for( pobject = start; pobject->next; pobject = pobject->next );
  85. nobject = (global_object*) malloc( sizeof( global_object ) );
  86. /* Should this be enough to fail global_add, and therefore also fail
  87. * dlopen?
  88. */
  89. if( !nobject )
  90. return;
  91. pobject->next = nobject;
  92. nobject->next = NULL;
  93. nobject->previous = pobject;
  94. nobject->hModule = hModule;
  95. }
  96. static void global_rem( global_object *start, HMODULE hModule )
  97. {
  98. global_object *pobject;
  99. if( hModule == NULL )
  100. return;
  101. pobject = global_search( start, hModule );
  102. if( !pobject )
  103. return;
  104. if( pobject->next )
  105. pobject->next->previous = pobject->previous;
  106. if( pobject->previous )
  107. pobject->previous->next = pobject->next;
  108. free( pobject );
  109. }
  110. /* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
  111. * static buffer.
  112. * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
  113. * the limit.
  114. */
  115. static CHAR error_buffer[65535];
  116. static CHAR *current_error;
  117. static char dlerror_buffer[65536];
  118. static int copy_string( CHAR *dest, int dest_size, const CHAR *src )
  119. {
  120. int i = 0;
  121. /* gcc should optimize this out */
  122. if( !src || !dest )
  123. return 0;
  124. for( i = 0 ; i < dest_size-1 ; i++ )
  125. {
  126. if( !src[i] )
  127. break;
  128. else
  129. dest[i] = src[i];
  130. }
  131. dest[i] = '\0';
  132. return i;
  133. }
  134. static void save_err_str( const CHAR *str )
  135. {
  136. DWORD dwMessageId;
  137. DWORD pos;
  138. dwMessageId = GetLastError( );
  139. if( dwMessageId == 0 )
  140. return;
  141. /* Format error message to:
  142. * "<argument to function that failed>": <Windows localized error message>
  143. */
  144. pos = copy_string( error_buffer, sizeof(error_buffer), UNICODE_L("\"") );
  145. pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str );
  146. pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, UNICODE_L("\": ") );
  147. pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId,
  148. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  149. error_buffer+pos, sizeof(error_buffer)-pos, NULL );
  150. if( pos > 1 )
  151. {
  152. /* POSIX says the string must not have trailing <newline> */
  153. if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
  154. error_buffer[pos-2] = '\0';
  155. }
  156. current_error = error_buffer;
  157. }
  158. static void save_err_ptr_str( const void *ptr )
  159. {
  160. CHAR ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
  161. #ifdef UNICODE
  162. # if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) )
  163. swprintf_s( ptr_buf, 19, UNICODE_L("0x%p"), ptr );
  164. # else
  165. swprintf(ptr_buf, 19, UNICODE_L("0x%p"), ptr);
  166. # endif
  167. #else
  168. snprintf( ptr_buf, 19, "0x%p", ptr );
  169. #endif
  170. save_err_str( ptr_buf );
  171. }
  172. void *dlopen( const char *file, int mode )
  173. {
  174. HMODULE hModule;
  175. UINT uMode;
  176. current_error = NULL;
  177. /* Do not let Windows display the critical-error-handler message box */
  178. uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  179. if( file == 0 )
  180. {
  181. HMODULE hAddtnlMods[1024]; // Already loaded modules
  182. HANDLE hCurrentProc = GetCurrentProcess( );
  183. DWORD cbNeeded;
  184. /* POSIX says that if the value of file is 0, a handle on a global
  185. * symbol object must be provided. That object must be able to access
  186. * all symbols from the original program file, and any objects loaded
  187. * with the RTLD_GLOBAL flag.
  188. * The return value from GetModuleHandle( ) allows us to retrieve
  189. * symbols only from the original program file. For objects loaded with
  190. * the RTLD_GLOBAL flag, we create our own list later on. For objects
  191. * outside of the program file but already loaded (e.g. linked DLLs)
  192. * they are added below.
  193. */
  194. hModule = GetModuleHandle( NULL );
  195. if( !hModule )
  196. save_err_ptr_str( file );
  197. /* GetModuleHandle( NULL ) only returns the current program file. So
  198. * if we want to get ALL loaded module including those in linked DLLs,
  199. * we have to use EnumProcessModules( ).
  200. */
  201. if( EnumProcessModules( hCurrentProc, hAddtnlMods,
  202. sizeof( hAddtnlMods ), &cbNeeded ) != 0 )
  203. {
  204. DWORD i;
  205. for( i = 0; i < cbNeeded / sizeof( HMODULE ); i++ )
  206. {
  207. global_add( &first_automatic_object, hAddtnlMods[i] );
  208. }
  209. }
  210. auto_ref_count++;
  211. }
  212. else
  213. {
  214. CHAR lpFileName[MAX_PATH];
  215. int i;
  216. /* MSDN says backslashes *must* be used instead of forward slashes. */
  217. for( i = 0 ; i < sizeof(lpFileName) - 1 ; i ++ )
  218. {
  219. if( !file[i] )
  220. break;
  221. else if( file[i] == '/' )
  222. lpFileName[i] = '\\';
  223. else
  224. lpFileName[i] = file[i];
  225. }
  226. lpFileName[i] = '\0';
  227. /* POSIX says the search path is implementation-defined.
  228. * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
  229. * to UNIX's search paths (start with system folders instead of current
  230. * folder).
  231. */
  232. hModule = LoadLibraryEx(lpFileName, NULL,
  233. LOAD_WITH_ALTERED_SEARCH_PATH );
  234. /* If the object was loaded with RTLD_GLOBAL, add it to list of global
  235. * objects, so that its symbols may be retrieved even if the handle for
  236. * the original program file is passed. POSIX says that if the same
  237. * file is specified in multiple invocations, and any of them are
  238. * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
  239. * symbols will remain global.
  240. */
  241. if( !hModule )
  242. save_err_str( lpFileName );
  243. else if( (mode & RTLD_GLOBAL) )
  244. global_add( &first_object, hModule );
  245. }
  246. /* Return to previous state of the error-mode bit flags. */
  247. SetErrorMode( uMode );
  248. return (void *) hModule;
  249. }
  250. static void free_auto( )
  251. {
  252. global_object *pobject = first_automatic_object.next;
  253. if( pobject )
  254. {
  255. global_object *next;
  256. for ( ; pobject; pobject = next )
  257. {
  258. next = pobject->next;
  259. free( pobject );
  260. }
  261. first_automatic_object.next = NULL;
  262. }
  263. }
  264. int dlclose( void *handle )
  265. {
  266. HMODULE hModule = (HMODULE) handle;
  267. BOOL ret;
  268. current_error = NULL;
  269. ret = FreeLibrary( hModule );
  270. /* If the object was loaded with RTLD_GLOBAL, remove it from list of global
  271. * objects.
  272. */
  273. if( ret )
  274. {
  275. HMODULE cur = GetModuleHandle( NULL );
  276. global_rem( &first_object, hModule );
  277. if( hModule == cur )
  278. {
  279. auto_ref_count--;
  280. if( auto_ref_count < 0 )
  281. auto_ref_count = 0;
  282. if( !auto_ref_count )
  283. free_auto( );
  284. }
  285. }
  286. else
  287. save_err_ptr_str( handle );
  288. /* dlclose's return value in inverted in relation to FreeLibrary's. */
  289. ret = !ret;
  290. return (int) ret;
  291. }
  292. void *dlsym( void *handle, const char *name )
  293. {
  294. FARPROC symbol;
  295. HMODULE hModule;
  296. #ifdef UNICODE
  297. wchar_t namew[MAX_PATH];
  298. wmemset(namew, 0, MAX_PATH);
  299. #endif
  300. current_error = NULL;
  301. symbol = GetProcAddress( (HMODULE) handle, name );
  302. if( symbol != NULL )
  303. goto end;
  304. /* If the handle for the original program file is passed, also search
  305. * in all globally loaded objects.
  306. */
  307. hModule = GetModuleHandle( NULL );
  308. if( hModule == handle )
  309. {
  310. global_object *pobject;
  311. for( pobject = &first_object; pobject; pobject = pobject->next )
  312. {
  313. if( pobject->hModule )
  314. {
  315. symbol = GetProcAddress( pobject->hModule, name );
  316. if( symbol != NULL )
  317. goto end;
  318. }
  319. }
  320. for( pobject = &first_automatic_object; pobject; pobject = pobject->next )
  321. {
  322. if( pobject->hModule )
  323. {
  324. symbol = GetProcAddress( pobject->hModule, name );
  325. if( symbol != NULL )
  326. goto end;
  327. }
  328. }
  329. }
  330. end:
  331. if( symbol == NULL )
  332. {
  333. #ifdef UNICODE
  334. size_t converted_chars;
  335. size_t str_len = strlen(name) + 1;
  336. #if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) )
  337. errno_t err = mbstowcs_s(&converted_chars, namew, str_len, name, str_len);
  338. if (err != 0)
  339. return NULL;
  340. #else
  341. mbstowcs(namew, name, str_len);
  342. #endif
  343. save_err_str( namew );
  344. #else
  345. save_err_str( name );
  346. #endif
  347. }
  348. // warning C4054: 'type cast' : from function pointer 'FARPROC' to data pointer 'void *'
  349. #ifdef _MSC_VER
  350. #pragma warning( suppress: 4054 )
  351. #endif
  352. return (void*) symbol;
  353. }
  354. char *dlerror( void )
  355. {
  356. char *error_pointer = dlerror_buffer;
  357. /* If this is the second consecutive call to dlerror, return NULL */
  358. if (current_error == NULL)
  359. {
  360. return NULL;
  361. }
  362. #ifdef UNICODE
  363. errno_t err = 0;
  364. size_t converted_chars = 0;
  365. size_t str_len = wcslen(current_error) + 1;
  366. memset(error_pointer, 0, 65535);
  367. # if ((defined(_WIN32) || defined(WIN32)) && (defined(_MSC_VER)) )
  368. err = wcstombs_s(&converted_chars,
  369. error_pointer, str_len * sizeof(char),
  370. current_error, str_len * sizeof(wchar_t));
  371. if (err != 0)
  372. return NULL;
  373. # else
  374. wcstombs(error_pointer, current_error, str_len);
  375. # endif
  376. #else
  377. memcpy(error_pointer, current_error, strlen(current_error) + 1);
  378. #endif
  379. /* POSIX says that invoking dlerror( ) a second time, immediately following
  380. * a prior invocation, shall result in NULL being returned.
  381. */
  382. current_error = NULL;
  383. return error_pointer;
  384. }
  385. #ifdef SHARED
  386. BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
  387. {
  388. (void) hinstDLL;
  389. /*
  390. * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
  391. *
  392. * When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap
  393. * memory only if the DLL is being unloaded dynamically (the lpReserved
  394. * parameter is NULL).
  395. */
  396. if( fdwReason == DLL_PROCESS_DETACH && !lpvReserved )
  397. {
  398. auto_ref_count = 0;
  399. free_auto( );
  400. }
  401. return TRUE;
  402. }
  403. #endif