# open_dll

Definition: | atom a = open_dll(sequence filename, bool bCrash=true)
Description: | Open a Windows dynamic link library (.dll) file, or a Linux shared library (.so) file. filename: including .dll/so and relative or absolute path, or a sequence of such [or "", see technicalia]. bCrash: controls whether to crash (default since 1.0.2) or return 0 on failure (when false [and filename!=""]) A base address will be returned, or 0 if the file cannot be found and bCrash is false [or filename==""]. On Windows the normal search path is used for for locating .dll files.
pwa/p2js: | Not supported.
Comments: | The value returned by open_dll() can be passed to define_c_proc(), define_c_func(), or define_c_var(). You can open the same .dll or .so file multiple times. No extra memory is used and you will get the same address returned each time. Phix closes the .dll or .so for you automatically at the end of execution. A 32-bit application can only open 32-bit dll/so files, and likewise a 64-bit application can only open 64-bit dll/so files. On 64-bit windows, somewhat confusingly, 64-bit dlls are typically kept in C:\Windows\System32, while 32-bit dlls are stored in C:\Windows\SysWOW64. They can also just be kept in the application directory, and sometimes in Phix\builtins, and in the case of pGUI the windows dlls are kept in demo\pGUI\win32 and demo\pGUI\win64 directories. On windows you may see .dll files explicitly identifed with the version and/or machine word size, eg libcurl32.dll and/or libcurl64.dll, or even libcurl-7.57.0-32.dll. For standalone dlls you may be able to perform a similar renaming yourself, however it may prevent inter-dependent dlls from loading, and therefore (say) \32\libcurl.dll and|or \64\libcurl.dll and perhaps specific version identifiers in the path is recommended instead. On linux, .so files are typically built/installed by a package manager or script, and it is generally unwise to attempt similar renaming tricks manually (or worry about where they were installed). Note that, especially on Windows, a relative or absolute path in the filename is not transferred to the opening of any dependent dlls, for instance there are about 20 heavily co-dependent windows gtk dlls. In such cases it is necessary to (temporarily) chdir() to the correct directory rather than specify that in the filename, and usually restore the current directory once the dlls have been successfully opened. Another example is that mpfr(32|64).dll depends on mpir(32|64).dll - you might (were mpfr.e not handling all this for you anyway) get away with opening mpir first, but you might not, it all depends on the build/link options used when they were originally compiled, and of course that might change (without your consent) between different release versions. One way round that has been in legacy programs to chuck things in C:\Windows(\System32|\SysWOW64), but that can mean installing one program breaks another, so avoid doing that if you can, and keep them in app-specific or versioned and quite possibly/often separate 32|64 directories instead. Of course there is no harm in several apps sharing a common dll storage space, for instance ...\libcurl-7.57.0\64\libcurl.dll, and in an ideal world you would (at install) create that if it does not already exist, but otherwise carefully byte-check and raise the alarm if there is any discrepancy, since that might help catch corrupt downloads and/or malware infected files.
Example: |
    atom knl32 = open_dll("kernel32.dll") -- crash on failure
    --if knl32=0 then crash(...) end if -- (no longer helpful)
    atom user32 = open_dll("user32.dll",false) -- don’t crash (legacy mode)
    if user32=0 then
        puts(1, "Could not open user32.dll!\n")
    end if
Pre-1.0.2 code should add the ",false" if it performs any checking such as that "if user32=0 then" above, and/or tries in several different directories, and as shown some now pointless [esp basic/crude] error handling can be removed. Legacy "link_c_func()" style routines, whose only purpose was to crash on failure, can now safely be removed, as long as said message was not more helpful, for instance pEmit2.e reports the error on user code rather than in itself.
Implementation: | See builtins\VM\pcfunc.e (an autoinclude) for details of the actual implementation.
See Also: | define_c_func, define_c_proc, define_c_var, c_func, c_proc, Calling C Functions
Technicalia | On Linux (unlike Windows), should define_c_func/proc be passed 0/NULL for the library, it automatically searches all open shared libraries. Some legacy code contains open_dll(""), which is quite obviously utterly pointless (it just returns 0/NULL), and only ever worked on Linux, however compatibility with that behaviour has been maintained. With the 1.0.2 changes [bCrash added], I also decided to drop "support" for (eg) open_dll({'u','s','e','r','3','2','.','d','l','l'}), but the previous [left in as comments] code can trivially be restored [by anyone] should that cause any unnecessary grief. You should also note that p (as in the Linux version of p.exe) depends on libc and libdl (you can check that using demo\pGUI\filedump.exw), whereas Euphoria’s eui also relies on libm, and hence you may find some old Euphoria code, which uses that "trick" to declare libm functions, will not work on Phix - and of course that can normally be rectified simply by replacing `libm = open_dll("")` by/with or adding `libm = open_dll("libm.so")`.