I can compile DLLs properly using mingw and do the exports/imports stuff. What I am looking for is defining the dll onload function properly as you would in MS VC products. Google didn't turn up anything. Anyone have any ideas or a link to a tutorial?
Okay, so after some fiddling...it's working. For anyone else that is having issues here it is. My issues weren't related to compiling in instead of loading dynamically. It was a mash-up of a couple of tutorial/question/how-tos that got me to this point.
dll.c
#include <stdio.h>
#include <windows.h>
#include "dll.h"
//extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD Reason, LPVOID LPV) {
//This one was only necessary if you were using a C++ compiler
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// Code to run when the DLL is loaded
printf ("Load working...\n");
break;
case DLL_PROCESS_DETACH:
// Code to run when the DLL is freed
printf ("Unload working...\n");
break;
case DLL_THREAD_ATTACH:
// Code to run when a thread is created during the DLL's lifetime
printf ("ThreadLoad working...\n");
break;
case DLL_THREAD_DETACH:
// Code to run when a thread ends normally.
printf ("ThreadUnload working...\n");
break;
}
return TRUE;
}
EXPORT void hello(void) {
printf ("Hello\n");
}
dll.h
#ifndef DLL_H_
#define DLL_H_
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif
EXPORT void hello(void);
#endif /* DLL_H_ */
hello.c
#include <windows.h>
#include <stdio.h>
int main () {
/*Typedef the hello function*/
typedef void (*pfunc)();
/*Windows handle*/
HANDLE hdll;
/*A pointer to a function*/
pfunc hello;
/*LoadLibrary*/
hdll = LoadLibrary("message.dll");
/*GetProcAddress*/
hello = (pfunc)GetProcAddress(hdll, "hello");
/*Call the function*/
hello();
return 0;
}
when compiled with
gcc -c -DBUILD_DLL dll.c
gcc -shared -o message.dll dll.o -Wl,--out-implib,libmessage.a
gcc -c hello.c
gcc -o hello.exe hello.o message.dll
produces the expected output of
Load working...
Hello
Unload working...
Since mingw is just a windows port of GCC and associated tools, you can use GCC constructor and destructor attributes. These work for both shared and static libraries, and execute code before and after main is run, respectively. Additionally, you can specify multiple constructor and destructor functions per library.
static void __attribute__((constructor))
your_lib_init(void)
{
fprintf(stderr, "library init\n");
}
static void __attribute__((destructor))
your_lib_destroy(void)
{
fprintf(stderr, "library destroy\n");
}
Related
I have a Windows 10 64-bits, Office 2013 32-bits and using MinGW64.
I followed instructions from https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/
I checked other answers threads in stackoverflow without success.
When I run Excel VBA code I get the follow error: "Run-Time error 48: File not found", but the file is in the folder and the folder has PATH reference.
I have the Add.c with follow code:
#include "add.h"
#include <windows.h>
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
/* Code path executed when DLL is loaded into a process's address space. */
break;
case DLL_THREAD_ATTACH:
/* Code path executed when a new thread is created within the process. */
break;
case DLL_THREAD_DETACH:
/* Code path executed when a thread within the process has exited *cleanly*. */
break;
case DLL_PROCESS_DETACH:
/* Code path executed when DLL is unloaded from a process's address space. */
break;
}
return TRUE;
}
int ADDCALL Add(int a, int b)
{
return (a + b);
}
/* Assign value to exported variables. */
int foo = 7;
int bar = 41;
The follow Add.h code:
/* add_var.h
Declares a function and variables to be imported by our application, and
exported by our DLL.
*/
/* You should define ADD_EXPORTS *only* when building the DLL. */
#ifdef ADD_EXPORTS
#define ADDAPI __declspec(dllexport)
#else
#define ADDAPI __declspec(dllimport)
#endif
/* Define calling convention in one place, for convenience. */
#define ADDCALL __cdecl
/* Make sure functions are exported with C linkage under C++ compilers. */
#ifdef __cplusplus
extern "C"
{
#endif
/* Declare our Add function using the above definitions. */
ADDAPI int ADDCALL Add(int a, int b);
/* Exported variables. */
extern ADDAPI int foo;
extern ADDAPI int bar;
#ifdef __cplusplus
} // __cplusplus defined.
#endif
And the follow VBA code to test:
Option Explicit
Private Declare PtrSafe Function Add Lib "C:\exceladd2\AddLib.dll" (ByVal a As Integer, ByVal b As Integer) As Integer
Sub Test()
Call MsgBox(Add(4, 5))
End Sub
The follow code was compiled with MinGW64 without errors or warnings:
x86_64-w64-mingw32-gcc-8.1.0 -c -o add.o add.c -D ADD_EXPORTS
x86_64-w64-mingw32-gcc-8.1.0 -o AddLib.dll add.o -shared -s -Wl,--subsystem,windows,--kill-at
The follow is the result from dependencies check from the library: https://pasteboard.co/J4zegPO.jpg
I tried to compile with gcc 32 bits and other versions of gcc 64-bits and got the same error 48 in Excel.
On the past I was able to run similar DLL compiled with gcc 32-bits in a Windows 7 32-bits with Office 2010 32-bit without any trouble. Ran Excel VBA with and without PtrSafe without result.
Is there anything wrong with code or compile?
Do you know any software to troubleshoot DLLs?
Thanks in advance for your help!
I need to generate a static library MyLib.lib that contains unimplemented functions.
Inside the project, I called the unimplemented function as shown below:
/* Inside MyLib.c */
#include "MyLib.h"
void foo(void)
{
func(); // To be implemented by the user.
}
And In the header file MyLib.h, I included a header file
#include "user.h" // contains user_imlplementation_of_func()
...
#define func() user_imlplementation_of_func()
To make things simple, let's just give an example of the user.c:
void user_imlplementation_of_func(void)
{
printf("OK");
}
I would like to know is it possible to do this call? Otherwise, Is there any other solution to use unimplemented functions inside a static library and let the user define them after compressing the project from a source code to a .lib file
You need to declare the unimplemented function as extern in the header of your library. This tells the compiler, that the function will be defined somewhere else.
Example:
MyLib.h
void foo();
extern void func();
MyLib.c
#include "MyLib.h"
void foo(void)
{
func();
}
main.c
#include <stdio.h>
#include "MyLib.h"
void func()
{
printf("Hello, world!\n");
}
int main()
{
foo();
}
Example build:
cc -o MyLib.o -c MyLib.c
cc -o out main.c MyLib.o
Output:
$ ./out
Hello, world!
However, for more readability I suggest you to pass your project functions as pointers to your library functions. This is commonly known as callback.
Example:
/* MyLib.c */
#include "MyLib.h"
void foo(void (*func)(void))
{
func();
}
Now you can call the foo function in your project with:
foo(&user_imlplementation_of_func);
Edit:
As stated in the comments by the user theSealion a third solution is the usage of weak symbols. The wikipedia articel "Weak symbol" provides a good explanation with examples.
You can do some else - function pointer:
//youLib.c
extern void (*func)(void) = NULL;
extern void foo()
{
if (func != NULL) {
func();
}
}
//main.c
static void user_imlplementation_of_func(void)
{
printf("Hello\n");
}
func = &user_imlplementation_of_func;
foo(); //Will printf "Hello"
i kept the essential.
caller.exe loads the dll, then calls the function dll_init declared inside the dll.
this last function calls the function "get_ptr" declared in the common library which should return a pointer to the global variable.
the issue is:
whenever caller.exe calls "get_ptr" it returns a valid pointer same as the one which was previously allocated on caller.exe start fine.
whenever the dll thru it function "dll_init" (after bein called by
caller.exe) calls "get_ptr" (knowing that the dll is linked to the
static lib) it return NULL pointer.
what i am missing ?
libcommon.c
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
/***************header****************/
int *get_ptr(void);
int set_ptr(void);
/**********************************/
int *global=NULL;
//extern __declspec(dllimport) int *global; doesnt work
int set_ptr() {
global = (int *) malloc(sizeof(int));
printf("global allocated to %p\n",global);
*global=485; //random value
return 0;
}
int *get_ptr() {
return global;
}
here is compiling commands (makefile simplified):
gcc.exe -c libcommon.c -o libcommon.o -m32
ar r libcommon.a libcommon.o
ranlib libcommon.a
module.c
#include <windows.h>
#include <stdio.h>
#if BUILDING_DLL
#define DLLIMPORT __declspec(dllexport)
#else
#define DLLIMPORT __declspec(dllimport)
#endif
DLLIMPORT int dll_init(void) {
int *ptr=(int *) get_ptr();
puts("dll run");
printf("from dll global: %p\n",ptr);
puts("dll end");
return 0;
}
compiling:
gcc.exe -c module.c -o module.o -m32 -DBUILDING_DLL=1
gcc.exe -shared module.o -o module.dll -static-libgcc -lws2_32 -m32 -s -L"." -lcommon -Wl,--output-def,libmodule.def,--out-implib,libmodule.a,--add-stdcall-alias
caller.c
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
typedef void(voidfunc)(void);
voidfunc *fct_ptr;
int test(int a) {
printf("%d",a++);
}
int main() {
set_ptr();
printf("::%p\n",get_ptr());
/* Load the dll then call dll_init */
HMODULE dllptr = LoadLibrary("module.dll");
if (dllptr != NULL) {
fct_ptr = (voidfunc *) GetProcAddress(dllptr, "dll_init");
puts("loaded");
if (fct_ptr != NULL)
fct_ptr();
FreeLibrary(dllptr);
}
}
compiling:
gcc.exe caller.c -o caller.exe -m32 -static-libgcc -lws2_32 -L. -lcommon -m32
I believe you have 2 different places in memory named global. One is
in caller since you compiled it statically with lcommon. Data is set
there via set_ptr. Second is in module space (for the same reasons),
but you never called set_ptr() there. Check memory address of global
inside dll_init and in main. If they are not the same, you then need
to call set_ptr in your `dll_init``
he's right, i think the common static library linked with both exe and dll was a wrong idea.
the solution is here: .dll Plugin that uses functions defined in the main executable
Any other suggestions are welcome
I created a DLL "Addition.dll" where i implemented hello function
These are the file that i used for the creation of the library:
main.cpp:
#include "main.h"
//Hello function
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_string(env, "Hello world!", ERL_NIF_LATIN1);
}
static ErlNifFunc nif_funcs[] =
{
{"hello", 0, hello}
};
ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)
/*************************DLL Main*******************************************/
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// attach to process
// return FALSE to fail DLL load
break;
case DLL_PROCESS_DETACH:
// detach from process
break;
case DLL_THREAD_ATTACH:
// attach to thread
break;
case DLL_THREAD_DETACH:
// detach from thread
break;
}
return TRUE; // successful
}
main.h:
#define __MAIN_H__
#include <windows.h>
#include <erl_nif.h>
#define DLL_EXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C"
{
#endif
/********************************Library functions******************************/
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
my goal is to call this function using an erlang module so i implemented "niftest.erl" as follow:
-module(niftest).
-export([init/0, hello/0]).
-on_load(init/0).
init() ->
erlang:load_nif("./Addition", 0).
hello() ->
"NIF library not loaded".
and of course put the Addition.dll in the same folder of "niftest.erl" but when i run niftest i have this error
4> c(niftest).
=ERROR REPORT==== 24-Apr-2015::11:43:17 ===
The on_load function for module niftest returned {error,
{load_failed,
"Failed to load NIF library ./Addition.dll: 'Le module spécifié est introuvable.'"}}
{error,on_load_failure}
thanks in advance for helping me
The pathname "./Addition" means you're attempting to load the NIF library from the current working directory, and it fails because the NIF is not there. Normally NIF libraries are stored under the application's priv directory, and you write code to locate it, something like this:
init() ->
SoName = filename:join(case code:priv_dir(?MODULE) of
{error, bad_name} ->
%% this is here for testing purposes
filename:join(
[filename:dirname(
code:which(?MODULE)),"..","priv"]);
Dir ->
Dir
end, "Addition"),
erlang:load_nif(SoName, 0).
Note the part that handles {error, bad_name}: this is handy for development purposes because if the application is not yet installed, this part will find the path to the module trying to load the NIF, assume the priv directory is a sibling to its directory, and attempt to load the NIF from there.
I had the same problem. In my case the error was that i compiled the dll by x32 platform but i had installed Erl x64.
I'm trying to embed LuaJIT into a C application. The code is like this:
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
int barfunc(int foo)
{
/* a dummy function to test with FFI */
return foo + 1;
}
int
main(void)
{
int status, result;
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
/* Load the file containing the script we are going to run */
status = luaL_loadfile(L, "hello.lua");
if (status) {
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
exit(1);
}
/* Ask Lua to run our little script */
result = lua_pcall(L, 0, LUA_MULTRET, 0);
if (result) {
fprintf(stderr, "Failed to run script: %s\n", lua_tostring(L, -1));
exit(1);
}
lua_close(L); /* Cya, Lua */
return 0;
}
the Lua code is like this:
-- Test FFI
local ffi = require("ffi")
ffi.cdef[[
int barfunc(int foo);
]]
local barreturn = ffi.C.barfunc(253)
io.write(barreturn)
io.write('\n')
It reports error like this:
Failed to run script: hello.lua:6: cannot resolve symbol 'barfunc'.
I've searched around and found that there're really little document on the ffi module. Thanks a lot.
ffi library requires luajit, so you must run lua code with luajit.
From the doc:
"The FFI library is tightly integrated into LuaJIT (it's not available as a separate module)".
How to embed luajit?
Look here http://luajit.org/install.html under "Embedding LuaJIT"
Under mingw your example run if i add
__declspec(dllexport) int barfunc(int foo)
at the barfunc function.
Under Windows luajit is linked as a dll.
As misianne pointed out, you need to export the function, which you can do by using extern if you are using GCC:
extern "C" int barfunc(int foo)
{
/* a dummy function to test with FFI */
return foo + 1;
}
If you are experiencing problems with undefined symbols under Linux using GCC, take care to have the linker add all symbols to the dynamic symbol table, by passing the -rdynamic flag to GCC:
g++ -o application soure.cpp -rdynamic -I... -L... -llua
For those of you trying to make this work on Windows with VC++ (2012 or later), using the C++ compiler:
make sure you use the .cpp extension, as this will do C++ compilation
make the function have external C linkage so that ffi can link to it, with extern "C" { ... }
export the function from the executable, with __declspec(dllexport)
optionally specify the calling convention __cdecl, not required because should be it by default and not portable
wrap the Lua headers in an extern "C" { include headers }, or better just #include "lua.hpp"
#include "lua.hpp"
extern "C" {
__declspec(dllexport) int __cdecl barfunc(int foo) {
return foo + 1;
}}