Load DLL Library - c

Is it possible to load a DLL with C and use its functions?
I am new in C, and I am trying to search some good references on the internet for this; but I can't find any.
Any help would be appreciated!
I am using GNU GCC in Code::Blocks on Windows 7, 64 Bit.

HMODULE hModule = LoadLibrary(<dll file name>) followed by GetProcAddress(hModule, <function name>) will do this job using the WinAPI.
An example could be found here.

I think you should investigate the LoadLibrary function.
http://msdn.microsoft.com/en-us/library/ms684175.aspx
Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded.

Building a DLL using MinGW, here are some instructions:
First, you need to mark your functions for export, so they can be used by callers of the DLL. To do this, modify them so they look like (for example)
__declspec( dllexport ) int add2(int num){
return num + 2;
}
then, assuming your functions are in a file called funcs.c, you can compile them:
gcc -shared -o mylib.dll funcs.c
The -shared flag tells gcc to create a DLL.
For a free IDE which will automate all the flags etc. needed to build DLLs, take a look at the excellent Code::Blocks, which works very well with MinGW.
Also, see the article Creating a MinGW DLL for Use with Visual Basic on the MinGW Wiki.

Related

Can you have multiple DLLs with common exports/ordinals and exchange at run-time?

I am trying to create a couple of Win32 64-bit DLLs (Windows 10) which have different implementations but consistent symbol exports. The aim for this is that one would link with whichever one at build time but have the option at deployment to install either DLL and correctly run with that. I have achieved this straightforwardly on Linux where I am much more comfortable and familiar with run-time linking. But on Windows, I have not yet managed this and I am wondering if this is possible at all. I am trying this using both VS2010 and VS2019.
Suppose I have two libraries blah_legacy.dll and blah_modern.dll. They both export 6 symbols which are the interface to using the library, e.g. blah_open, blah_read, blah_write, blah_close, blah_control, blah_status.
I can link with the import library for either blah implementation and a test program calling each symbol loads and executes correctly with the corresponding blah DLL.
However, I cannot yet switch the DLLs at run time. For example, should I actually be able to link with blah-legacy.lib and then run with blah-modern.dll if I rename it to blah-legacy.dll? (Or vice-versa.)
I already got around basic file-naming issues and ensured the DLL needed can actually be found. I still got the application failed to start (0x22).
I used "objdump -xs" on the DLLs and noticed the order of symbols and their ordinals are different. So I created a .def file and ensured that the exported symbols match in number, names and in ordinals. Still nothing - the same error occurs.
There's still something to this I clearly have not figured out and would appreciate some guidance. Is this actually possible? Where do I start to look (which tools) to figure out what step to take next.
Yes.
I don't use Visual Studio much, but this is the kind of thing that happens all the time if you use MSYS2, and install some MinGW packages, and update them.
Here's what I mean by that: MSYS2 is an open source software distribution for Windows that, among other things, provides a bunch of native Windows software packages. The package manager (pacman) let's you choose which packages to have in your system, and it downloads DLLs and EXEs that were created by the MSYS2 developers. When an MSYS2 developer updates a library, you can download the updated library package, and all the other packages using that library will automatically start using the new DLL. Usually there is no issue with that because the new library version will be ABI-compatible with the old library version.
You do not need to use LoadLibrary or otherwise mess up your source code; the linker and the operating system should be able to take care of this for you.
Example
Here is a minimal example I threw together with MSYS2 showing how this can work.
The file foo_legacy.c represents your legacy DLL. I added some extra symbols so it wouldn't be too similar to the modern DLL.
__declspec(dllexport) int eoo() {
return 0;
}
__declspec(dllexport) const char * foo_name() {
return "legacy";
}
__declspec(dllexport) int foo_version() {
return 1;
}
__declspec(dllexport) int goo() {
return 0;
}
The file foo_modern.c represents the modern implementation:
__declspec(dllexport) const char * foo_name(void);
__declspec(dllexport) int foo_version(void);
int foo_version() {
return 2;
}
const char * foo_name() {
return "modern";
}
The file main.c represents an application using the foo API:
#include <stdio.h>
__declspec(dllimport) const char * foo_name(void);
__declspec(dllimport) int foo_version(void);
int main()
{
printf("%s %d\n", foo_name(), foo_version());
}
My build.sh file is a Bash script that builds and tests everything:
#!/usr/bin/bash
set -uex
gcc -Wall foo_legacy.c -shared -o foo_legacy.dll
gcc -Wall foo_modern.c -shared -o foo_modern.dll
gcc -Wall -c main.c -I. -o main.o
gcc main.o foo_legacy.dll -o main.exe
./main.exe # output: "legacy 1"
mv foo_modern.dll foo_legacy.dll
./main.exe # output: "modern 2"
rm foo_legacy.dll
./main.exe # fails because foo_legacy.dll is not found
The build script runs main.exe three different times, showing that it can either use the legacy DLL, or use the modern DLL, or fail, depending on what was installed in foo_legacy.dll.

Using Libdl.dlopen kills Julia

I am trying to call a C code from Julia v0.6.2, Windows 10.
Here is the C code I compiled into a DLL with Cygwin gcc.
int timesTwo(int x) {
return 2*x;
}
The compile commands:
gcc -c mydll.c
gcc -shared -o mydll.dll mydll.o
I tested the DLL with a test C program and it works. Then I tried to call it with Julia using an absolute path to the DLL.
using Base.Libdl
x = Int32(2)
mylib = dlopen("C:\\Users\\pedro\\Documents\\codigos\\exampleDLL\\C\\mydll.dll")
ccall((:timesTwo, mylib), Int32, (Int32,), x)
Then the Julia's Workspace is restarted (all variables become undefined as soon as I use the command dlopen).
What is happening and how can I solve it?
Update
That must be a windows issue. Could not reproduce in an Ubuntu distro.
I would try to use the same compiler that Julia uses (with the -fPIC flag) to build your DLL. On Windows, julia is actually build with the
Cygwin-to-MinGW cross-compiler:
https://github.com/JuliaLang/julia/blob/master/README.windows.md#cygwin-to-mingw-cross-compiling
Can you install the mingw64-x86_64-gcc-core package (for just the C compiler) and use the x86_64-w64-mingw32-gcc compiler command (instead of gcc) ?
Use the -fPIC switch to generate the position independent code. Plus, you might be lying to Julia unless your int is defined as int32 on the specific platform. To be sure, you need to change ccall((:timesTwo, mylib), Int32, (Int32,), x) to ccall((:timesTwo, mylib), Cint, (Cint,), x). Finally, to make the code work for any operating system, please consider replacing mylib = dlopen("C:\\Users\\pedro\\Documents\\codigos\\exampleDLL\\C\\mydll.dll") to const mylib = dlopen(joinpath(pwd(), "mydll.dll")). const is there for efficiency reasons, joinpath is OS-agnostic, meaning that it will add forward slash for *nix-based systems. Later on, when you want to change the library to .so, for instance, you should not deal with slashes, too.

Unable to compile a c application that reads smartcard

I am trying to compile an example c application that is using pkcs#11 to finds all
the private keys on the token, and print their label and id, but getting following errors
/tmp/ccAqQ7UI.o: In function initialize':
pkcs11_example1.c:(.text+0x8e5): undefined reference to C_Initialize'
/tmp/ccAqQ7UI.o: In function `get_slot':
The example is taken from here
compilling by using following command;
`gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so`
I am not sure which library i should link after -L.
Can anyone guide how to compile this and are there some libraries required to link.
C_Initialize and other 60+ functions with "C_" prefix are cryptoki functions defined in PKCS#11 specification. They are usually implemented in standalone library provided by HSM vendor. Looking at your code samples I would say that you need to directly link also PKCS#11 library or you can modify the code to dynamically load PKCS#11 library in runtime with LoadLibrary or dlopen and then acquire pointers to all cryptoki functions via the C_GetFunctionList call. You can also take a look at pkcs11-logger the source code for an example on how to do that.
The link command you give, gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so, is wrong.
-L takes just path, which is added to paths where libs are searched from, but /usr/lib is default so you don't need this switch at all.
You are missing -l, which takes the library name without lib prefix or .so suffix, so looks like you need -lopensc-pkcs11.
So, first make sure your library file really is /usr/lib/libopensc-pkcs11.so (note lib prefix!) possibly with verion numbers following. Then change build options so link command becomes
gcc pkcs11_example1.c -o slots -lopensc-pkcs11

Link against a Windows .dll+.lib file combination with GCC under Cygwin?

I know how to link against libraries in Unix-ish contexts: If I'm working with .a or .so files, I specify the root search directory with -L/my/path/to/lib/ and for libMylib I add -lMyLib.
But what if I have
a .dll (e.g. in the Windows\System32 directory)?
a .dll (in Windows\System32) and a .lib (someplace else)?
These DLLs are by some other party; I don't have access to their sources - but do have access to the corresponding include files, against which I manage to compile.
If you can link against a .lib in Cygwin or MinGW, then you can (indirectly) link against a DLL.
In the MSVC world, it is not unusual to create an import library along with a DLL. It is a static library (.lib) that loads the DLL and wraps the interface of the DLL. You just call the wrapper functions in the (static) import library and let the import library do all the DLL-related things.
For the Windows API, there are import libraries in the WindowsSDK.
For your own MSVC DLLs, MSVC can automatically generate the import libraries when you build the DLL.
For a third party DLL, you can build a static wrapper library based on the corresponding header files.
Linking against the .lib file in Cygwin or MinGW is possible. Example:
g++ -o myprg myprg.o -lShlwapi
This links against Shlwapi.lib. (The library must be in the local directory or in the library path of the linker.)
Linking against import libraries of DLLs works the same way.
Note 1: Keep in mind the different ABIs and name mangeling. However, calling plain C functions in DLL or LIB files will work in most cases.
Note 2: Keep in mind that g++ requires the libraries to be specified in the correct order.
#einpoklum Converting my comment to an answer: #n.18e9 is correct in that you must use the full path name for the lib file without any -L or -l options.
g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. You can also link directly to the Windows DLL file g++ -o foo.exe foo.o c:\something\somethingelse\some.dll.
Important - make sure you are linking to a lib file (and associated dll) generated for a 64-bit platform (on MSVC target X64, not Win32).
OK you wanted an example, well let's go.
Here are two examples using gcc/g++ to link to a Windows native DLL which exports plain C functions (using here x86_64-w64-mingw32/8.3.0 on Windows 10).
I'm using my own free xmlsq library as an example https://www.cryptosys.net/xmlsq.
You can download the core native DLL and all the source code quoted below. Make sure you use the 64-bit DLL.
The native Windows DLL diXmlsq.dll is written entirely in plain C code and exports simple C functions (extern "C").
In particular, for this example, it exports a XMLSQ_Gen_Version function that returns an integer value.
The DLL was compiled using MSVC 12.0 targetting the X64 platform. The associated library file generated by MSVC is diXmlsq.lib.
I should add that this DLL works exactly the same as a Windows "Win32 API" DLL, so the instructions here should work for the standard Windows libraries in Windows\System32 (again make sure you link against the 64-bit version).
Example 1. A plain C interface.
Both these commands compile without warning on my system:
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.lib"
> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.dll"
diXmlsq.dll is compiled using the following definition file.
(You could alternatively use __declspec(dllexport))
Ref: https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll?view=msvc-160
diXmlsq.def
LIBRARY "diXmlsq"
EXPORTS
XMLSQ_Gen_Version
diXmlsq.h - the C interface to diXmlsq.dll
#ifdef __cplusplus
extern "C" {
#endif
long __stdcall XMLSQ_Gen_Version(void);
#ifdef __cplusplus
}
#endif
To call the core function in a plain C program:
test-ver.c
#include <stdio.h>
#include "diXmlsq.h"
int main(void)
{
long n;
n = XMLSQ_Gen_Version();
printf("Version = %ld\n", n);
return 0;
}
Example 2. A C++ interface.
Both these commands compile without warning using g++ .
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.lib"
> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.dll"
The idea of the C++ interface is to be an interface to the plain C library using the more convenient STL types like std::string and std::vector.
To keep things simple we'll just demonstrate the Gen::Version method.
Extracts of the C++ code follow:
test-simple.cpp - a test C++ program.
#include <iostream>
#include "xmlsq.hpp"
int main()
{
std::cout << "xmlsq::Gen::Version=" << xmlsq::Gen::Version() << std::endl;
}
xmlsq.hpp - the C++ interface
namespace xmlsq
{
class Gen {
private:
Gen() {} // Static methods only, so hide constructor.
public:
/** Get version number of core diXmlsq DLL. */
static int Version();
};
}
xmlsq.cpp - the C++ implementation.
#include "diXmlsq.h"
#include "xmlsq.hpp"
namespace xmlsq
{
int Gen::Version() {
int n = XMLSQ_Gen_Version();
return n;
}
}
Example 3. Attempting to link to the 32-bit library by mistake.
> gcc -o test-ver test-ver.c "C:\fullpath\to\Win32\diXmlsq.lib"
C:/Strawberry/c/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
C:\Users\user\AppData\Local\Temp\cce27Dhl.o:test-ver.c:(.text+0xe):
undefined reference to `XMLSQ_Gen_Version'
collect2.exe: error: ld returned 1 exit status

What's the equivalent of gcc's -mwindows option in cmake?

I'm following the tuto:
http://zetcode.com/tutorials/gtktutorial/firstprograms/
It works but each time I double click on the executable,there is a console which I don't want it there.
How do I get rid of that console?
I tried this:
add_executable(Cmd WIN32 cmd.c)
But got this fatal error:
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain#16 referenced in function ___tmainCRTStartup
Cmd.exe : fatal error LNK1120: 1 unresolved externals
While using gcc directly works:
gcc -o Cmd cmd.c -mwindows ..
I'm guessing it has something to do with the entry function: int main( int argc, char *argv[]),but why gcc works?
How can I make it work with cmake?
UPDATE
Let me paste the source code here for convenience:
#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_show(window);
gtk_main();
return 0;
}
UPDATE2
Why gcc -mwindows works but add_executable(Cmd WIN32 cmd.c) not?
Maybe that's not the equivalent for -mwindows in cmake?
add_executable(Cmd WIN32 cmd.c)
Tells CMake this is a Windows program, and it looks for WinMain instead of main. If you want to see the flags being used you can run make VERBOSE=1. The question might be how do you define WinMain for gtk apps? I know with Qt, you link in a library that defines it for you.
You can set these linker flags to have a main() entry point and no console:
SET(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} /subsystem:windows /ENTRY:mainCRTStartup")
For more info, see this answer for the linker flags, and this answer for how to set flags in cmake.
For CMake 3.13 and newer you can use
target_link_options(target PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
If you want your program to run in console mode (ie a main function), you have to specify it in your project's properties in MSVC. What you're using right now is a project in windowed mode (ie a WinMain function, which you don't have, hence the error).
But if you don't want to get the ugly console window, you want to use the windowed mode (ie transform your main function into a propper WinMain function). This way your normal window is all that will show.
edit: As an aside, you really shouldn't name your program "cmd", that's the name of Windows' command interpreter.
According to the CMake documentation for using the WIN32 flag with ADD_EXECUTABLE:
When this property is set to true the executable when linked on Windows will be created with a WinMain() entry point instead of of just main().This makes it a GUI executable instead of a console application. See the CMAKE_MFC_FLAG variable documentation to configure use of MFC for WinMain executables.
However, your program's entry point is main() and not WinMain(). What you should do, instead, is omit the WIN32 flag, but you need to link against libgtk. So, you would use TARGET_LINK_LIBRARIES:
FIND_PACKAGE(GTK2 2.6 REQUIRED gtk)
INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})
LINK_DIRECTORIES(${GTK2_LIBRARIES})
ADD_EXECUTABLE(myprogramname source1 source2 ... sourceN)
TARGET_LINK_LIBRARIES(myprogramname ${GTK2_LIBRARIES})
While the accepted answer works for MinGW, it won't work for MSVC when you don't define a WinMain. No answer is cross-toolchain compatible IMHO.
Fix Subsystem
add_executable(my_exe WIN32 main.c)
basically passes -mwindows if MinGW compiler is used or /SUBSYSTEM:WINDOWS if MSVC. This sets the subsystem field in PE header of the generated executable to 2 i.e. IMAGE_SUBSYSTEM_WINDOWS_GUI. This instructs Windows to not provide a separate console window for this executable.
Fix Entry Point on MSVC
When MSVC receives /SUBSYSTEM:WINDOWS, its runtime expects1 a WinMain, not main, to be defined unlike MinGW's (which works with any one defined). If you want to continue to use main, fix the entry point:
target_link_options(my_exe PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/ENTRY:mainCRTStartup>
)
1: Yes, OS first calls C runtime and it's the C runtime which calls your executable's entry point
Fix Subsystem Per-config
add_executable(my_exe WIN32 ... internally sets the executable's WIN32_EXECUTABLE property. This gives another, more useful way to do it:
add_executable(my_exe main.c) # look ma, no WIN32!
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE 1)
This is useful when you want to do it only for some configurations. I personally enable this only on Release builds, while having a console window on Debug builds is useful.
# No console window for non-debug builds
set_target_properties(my_exe PROPERTIES WIN32_EXECUTABLE
$<AND:$<PLATFORM_ID:Windows>,$<NOT:$<CONFIG:Debug,RelWithDebInfo>>>
)
Verify
# Generate Ninja files for GCC
cmake -B build_g -G "Ninja Multi-Config"
# Generate Visual Studio project and solution for MSVC
cmake -B build_v -G "Visual Studio 17 2022"
# Build with verbosity
cmake --build build_g --config Release -v
This should show the actual build commands with parameters in full verbosity. Useful to verify if -mwindows or /SUBSYSTEM:WINDOWS is passed for the right build configurations.

Resources