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.
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 have a DLL
A.dll
This is A.h
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
#define DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllexport)
#endif
DLL_EXPORT void function();
DLL_EXPORT char ** ReturnArr;
This is A.c
void function()
{
char *str = "hello";
char *str1 = "how are you?";
ReturnArr = (char **)malloc(sizeof(char*) * 2);
for(;j<2;j++)
{
ReturnArr[j] = (char *) malloc(256);
if(NULL == ReturnArr[j])
break;
}
strcpy(ReturnArr[0],"str");
strcpy(ReturnArr[1],"str1");
}
Now i have Application.c that would use dll
#include <windows.h>
#include <stdio.h>
typedef int (__cdecl *MYPROC)(LPWSTR);
_declspec(dllimport) char ** ReturnArr;
int main( void )
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
int a = 0;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary(TEXT("A.dll"));
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "function");
// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (L"Message sent to the DLL function\n");
printf("%s",Returnarr[0]);
}
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message printed from executable\n");
return 0;
}
In Visual studio CommonProperties->references:i added A.dll its showing me compiler ##error Error 1 error LNK2001: unresolved external symbol "__declspec(dllimport) char * ##* ReturnArr" (_imp?ReturnArr##3PAPADA)" and "Error 2 fatal error LNK1120: 1 unresolved ##externals"
how can i actually export a Global variable and use in my application,tell me a way how can i actually print ReturnArr as a global variable in my application
thanks
If you want the linker to resolve the ReturnArr imported variable, you have to add A.LIB to the link process. There are several ways to do this.
Add A.LIB to the "additionnal dependecies" in Configuration properties->Linker->Input
Add #pragma comment( lib, "a.lib" ) in Application.c
Make the DLL project a dependency of the EXE project and in the EXE project and set the Configuration properties->linker->General "Link Library dependencies" to yes.
Side notes:
Are you sure yoy want strcpy(ReturnArr[0],"str"); ? Could be
strcpy(ReturnArr[0],str); (without the quote around str)
If you statically link to A, you don't need to LoadLibrary and GetProcAddress.
You could also just supress _declspec(dllimport) char ** ReturnArr;
Your typedef for MYPROC is wrong. The return type of "function" is void, not int
If you want the EXE to know about the ReturnArr, just make it the return value of function!
You should try to explain what exactly you are trying to do
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");
}
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;
}}
I have following function defined in one dll:
__declspec( dllexport ) int __stdcall
mjscall(char *cmd, DWORD wtime, char *stdoutfile, char *stderrfile )
I need to write one process to call the above function.
I am doing it first time,I do not have much idea.
I have written the following code
#include <windows.h>
#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <limits.h>
extern __declspec( dllexport ) int __stdcall mjscall(char *cmd, DWORD wtime, char *stdoutfile, char *stderrfile );
typedef INT (*MJSCALL) (char *,DWORD, char *, char *);
int main()
{
char *a,*b,*c;
a=NULL;
b=NULL;
c=NULL;
DWORD aa =1;
int i;
HMODULE hLib;
MJSCALL ADD;
hLib=LoadLibrary("f3cucall.dll");
if(hLib==NULL)
{
return 1;
}
ADD=(MJSCALL)GetProcAddress(hLib,"mjscall");
if (ADD==NULL)
{
return 1;
}
(ADD)(a,aa,b,c);
return 0;
}
The "(ADD)(a,aa,b,c);" is causing the problem.
Can somebody help me out?
I think you mixed two things up:
the __declspec(dllexport) MSVC keyword exports functions from a DLL (tells the linker to do so), and the __declspec(dllimport) imports functions from a DLL. This is done at loading time, the linker will create all the necessary code to load the DLL and resolve the symbol. In fact, it adds some code to the exe to let the OS load the DLL. You can use functions declared with __declspec(dllimport) just like any normal internal function.
If you want to use this approach, you need the DLL's lib file, since it contains information for the linker to resolve the symbolic name. It doesn't actually contain code, only these information on the DLL for the linker. Additionally, you have to tell the linker that the function you want to use is located at a DLL, using the magic __declspec(dllimport) before the function declaration. That's why you provide a .lib and a header file (containing these declarations) with your DLL if you want to do it this way. You should rebuild the project that uses the DLL when you change the DLL, as the .lib file may have changed.
You can use the same header file in your DLL project and the projects that import from this DLL:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
MYDLL_API void printMe(int);
The MyDLL_API get resolved to either __declspec(dllexport) (in the DLL project, where you define the MYDLL_EXPORTS in the project settings) or __declspec(dllimport) (in all projects that use the dll). This way, you only need one header file for the DLL.
Another method of calling DLL functions is to use LoadLibrary and GetProcAdress. These two are used to load a DLL at runtime. The main difference between loading a DLL at loading time and at runtime is that you have some control over loading the DLL at runtime, whereas the OS will do the job when the DLL is to load at loading time (e.g. show a message box if the DLL cannot be found and do not run the process).