I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.
Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}
You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif
Related
This question already has answers here:
Exporting functions from a DLL with dllexport
(4 answers)
Closed 4 years ago.
I have a fucntion in dynamic library which looks like:
namespace Dll {
int MyDll::getQ() {
srand(time(0));
int q = rand();
while (!isPrime(q) || q < 100) {
q = rand();
}
return q;
}
}
Function getQ() in .h file:
#ifdef _EXPORT
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
namespace Dll
{
class MyDll
{
public:
static DLL_EXPORT int __stdcall getQ();
}
}
And finally LoadLibrary peace of code from another consoleApp:
typedef int(__stdcall *CUSTOM_FUNCTION)();
int main()
{
HINSTANCE hinstance;
CUSTOM_FUNCTION proccAddress;
BOOL freeLibrarySuccess;
BOOL proccAddressSuccess = FALSE;
int result;
hinstance = LoadLibrary(TEXT("Dll.dll"));
if (hinstance != NULL)
{
proccAddress = (CUSTOM_FUNCTION)GetProcAddress(hinstance, "getQ");
if (proccAddress != NULL)
{
proccAddressSuccess = TRUE;
result = (*proccAddress)();
printf("function called\n");
printf("%d", result);
}
freeLibrarySuccess = FreeLibrary(hinstance);
}
if (!hinstance)
printf("Unable to call the dll\n");
if (!proccAddressSuccess)
printf("Unable to call the function\n");
}
So I tried to fix this several times but I always get "Unable to call the function". The code connects to the library so the problem is somewhere near the function.
I'll appreciate if someone will point me on my mistake.
You are missing an Extern "C".
If you don't, names will be c++ mangled and you cannot find them with getQ name only. In addition, it will not be reliable to do so, because name mangling may change.
Another topic is here to: _stdcall vs _cdecl
I'm trying to write a C++ program that will communicate with different DB providers. Everything works fine now, however upon exiting I'm trying to close the connection and the disconnect command crashes. At the moment I'm testing with SQLite, so it probably belong to this specific one.
Do I have to close the connection to the SQLite upon program termination? I believe generally it is a good idea to release the resources the program is using, but what about this case? I mean in this case the SQLite DB file will be released back to the system when the program exits, so its not actually a loss.
Thank you.
[EDIT]
As requested I'm submitting the code that I use.
In DLL1 (database.h):
#ifndef DBMANAGER_DATABASE
#define DBMANAGER_DATABASE
class __declspec(dllexport) Database
{
public:
Database();
virtual ~Database();
static void *operator new(size_t size);
static void operator delete(void *ptr, size_t size);
};
#endif
In DLL1 (database.cpp)
#include <string>
#include "database.h"
Database::Database()
{
}
Database::~Database()
{
}
void *Database::operator new(std::size_t size)
{
return ::operator new( size );
}
void Database::operator delete(void *ptr, std::size_t size)
{
return ::operator delete( ptr );
}
In DLL2: (database_sqlite.h):
#ifndef DBMANAGER_SQLITE
#define DBMANAGER_SQLITE
class __declspec(dllexport) SQLiteDatabase : public Database
{
public:
SQLiteDatabase();
virtual ~SQLiteDatabase();
virtual int Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg);
protected:
void GetErrorMessage(int code, std::wstring &errorMsg);
private:
sqlite3 *m_db;
};
#endif
In DLL2: (database_sqlite.cpp)
#ifdef WIN32
#include <windows.h>
#pragma execution_character_set("utf-8")
#endif
#include <vector>
#include <string>
#include <sqlext.h>
#include "sqlite3.h"
#include "database.h"
#include "database_sqlite.h"
SQLiteDatabase::SQLiteDatabase() : Database()
{
}
SQLiteDatabase::~SQLiteDatabase()
{
sqlite3_close( m_db );
}
int SQLiteDatabase::Connect(const char *selectedDSN, std::vector<std::wstring> &errorMsg)
{
int result = 0;
std::wstring errorMessage;
int res = sqlite3_open( selectedDSN, &m_db );
if( res != SQLITE_OK )
{
// get error messages GetErrorMessage( res, errorMessage );
errorMsg.push_back( errorMessage );
result = 1;
}
else
{
res = sqlite3_exec( m_db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL );
if( res != SQLITE_OK )
{
// get error message GetErrorMessage( res, errorMessage );
errorMsg.push_back( errorMessage );
result = 1;
}
}
return result;
}
In DLL3: (dialogs.cpp)
#ifdef __GNUC__
#pragma implementation "dialogs.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include <vector>
#include "sqlite3ext.h"
#include "database.h"
#include "database_sqlite.h"
#ifdef _WINDOWS
BOOL APIENTRY DllMain( HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
lpReserved = lpReserved;
hModule = hModule;
int argc = 0;
char **argv = NULL;
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif
extern "C" __declspec(dllexport) Database *DatabaseProfile(Database *db)
{
db = new SQLiteDatabase;
return db;
}
In main application (test_app.cpp):
#include "stdafx.h"
#include "database.h"
#include <windows.h>
#include <stdio.h>
typedef Database *(__cdecl *MYFUNC)(Database *);
class A
{
public:
A(Database *db)
{
m_db = NULL;
HINSTANCE hInst = LoadLibrary( TEXT( "dialogs.dll" ) );
MYFUNC func = (MYFUNC) GetProcAddress( hInst, "DatabaseProfile" );
m_db = func( db );
}
~A()
{
}
Database *GetDatabase()
{
return m_db;
}
private:
Database *m_db;
};
int _tmain(int argc, _TCHAR* argv[])
{
Database *db = NULL, *m_db;
A *a = new A( db );
m_db = a->GetDatabase();
delete m_db;
delete a;
return 0;
}
[EDIT]
Running this code I am getting the crash executing "delete "m_db" line. SQLite is compiled in from source code.
Any idea?
Thank you.
I'm trying to create a cross-platform program. I just created a class and made a function which gets the path of the current user. I wanted to use that path later. But somehow I get these errors :
"/usr/include/x86_64-linux-gnu/sys/stat.h:-1: In member function 'void FileManager::p_getfilepath()':"
"/usr/include/x86_64-linux-gnu/sys/stat.h:105: error: expected unqualified-id before string constant"
"/home/david/VocabularyTrainer/filemanager.cpp:31: error: expected '}' at end of input"
btw the 31th line is the last line here in this code :
void FileManager::p_getfilepath()
{
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
Anyone knows what's wrong? I'm on linux mint.
By including your headers inside your class functions, you're making everything in the header a part of the function.
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
#endif
void FileManager::p_getfilepath()
{
#ifdef Q_OS_LINUX
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
Well I am tryng to have a queue which is concurrent, but concurrency_queue isn't standard C++ and it's for windows, linux doesn't have it. Is there anything for linux like this (with the same functions like in the windows equivalent?)?
Edit:
This is needed to port this windows code to linux:
#include <concurrent_queue.h>
#ifdef defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define SLEEP(x) { Sleep(x); }
#include <windows.h>
#include <process.h>
#define OS_WINDOWS
#define EXIT_THREAD() { _endthread(); }
#define START_THREAD(a, b) { _beginthread( a, 0, (void *)( b ) ); }
#else
#include <pthread.h>
#define sscanf_s sscanf
#define sprintf_s sprintf
#define EXIT_THREAD() { pthread_exit( NULL ); }
#define START_THREAD(a, b) { pthread_t thread;\
pthread_create( &thread, NULL, a, (void *)( b ) ); }
#endif
using namespace std;
using namespace Concurrency;
struct QuedData
{
int start;
int end;
int extraid;
AMX * script;
QuedData(){start = 0;end = 0;extraid = 0;script = NULL;}
QuedData(int start_,int end_,int extraid_, AMX * script_){start = start_;end = end_;extraid = extraid_;script = script_;}
};
struct PassData //thanks to DeadMG for improvements.
{
std::vector<cell> Paths;
int extraid;
AMX * script;
cell MoveCost;
PassData(){extraid = 0;script = NULL;MoveCost = 0;Paths.clear();}
template<typename Iterator> PassData(Iterator begin, Iterator end, int extraid_, cell MoveCost_, AMX * script_)
: Paths(begin, end)
{extraid = extraid_;MoveCost = MoveCost_;script = script_;}
~PassData(){Paths.clear();}
};
concurrent_queue <QuedData> QueueVector;
concurrent_queue <PassData> PassVector;
PassData LocalPass;
void PLUGIN_CALL
ProcessTick()
{
if(PassVector.try_pop(LocalPass))
{
amx_Push(LocalPass.script, LocalPass.MoveCost);
//blabla
}
}
static cell AMX_NATIVE_CALL n_CalculatePath( AMX* amx, cell* params )
{
QueueVector.push(QuedData(params[1],params[2],params[3],amx));
return 1;
}
bool PLUGIN_CALL Load( void **ppData )
{
START_THREAD( Thread::BackgroundCalculator, 0);
return true;
}
QuedData RecievedData;
vector <cell>tbcway;
cell tbccostx;
#ifdef OS_WINDOWS
void Thread::BackgroundCalculator( void *unused )
#else
void *Thread::BackgroundCalculator( void *unused )
#endif
{
while( true ){
if(QueueVector.try_pop(RecievedData)){
dgraph->findPath_r(xNode[RecievedData.start].NodeID ,xNode[RecievedData.end].NodeID,tbcway,tbccostx);
PassVector.push(PassData(tbcway.begin(),tbcway.end(),RecievedData.extraid,tbccostx,RecievedData.script));
}
SLEEP(5);
}
EXIT_THREAD();
}
The Visual C++ concurrent_queue is actually based on the Intel Threading Building Block Library
(If you open concurrent_queue.h header file in VC++ you will see an acknowledgement)
You can get the library from
http://threadingbuildingblocks.org/
The library will run on Linux as well.
I think threadpool does this or an unofficial Boost enhancement called lockfree and should by now be part of Boost::Atomics. I haven't use both but let us know if you have any luck.
I would suggest looking at https://github.com/romanek-adam/boost_locking_queue for the code and the article that goes with it at Implementing a Thread-Safe Queue using Condition Variables
I'm trying to write game using Ogre engine. I had a lot of problems - GCC didn't compiled program because it didn't found OgreMain_d and OIS_d... I created symbolic links (I'm using Linux) to libOgreMain.so.1.7.2 and libOIS-1.3.0.so and GCC compiled my program, but... the program shows error:
OGRE EXCEPTION(6:FileNotFoundException): 'resources.cfg' file not found! in ConfigFile::load at /home/m4tx/Programs/ogre_src_v1-7-2/OgreMain/src/OgreConfigFile.cpp (line 83)
My code:
#define OGRE_CHANGE1 ((1 << 16) | (1 << 8))
#include "Ogre.h"
#include "ExampleApplication.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#else
#include <iostream>
#endif
// Dziedziczymy ExampleApplication
class MyApp : public ExampleApplication
{
protected:
public:
MyApp()
{
}
~MyApp()
{
}
protected:
void createScene(void)
{
}
};
#ifdef __cplusplus
extern "C" {
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
MyApp App;
try
{
App.go();
return 0;
}
catch (Ogre::Exception& e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "Exception!",
MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr <<"Exception:\n";
std::cerr <<e.getFullDescription().c_str() <<"\n";
#endif
return 1;
}
}
#ifdef __cplusplus
}
#endif
Please help.
Your hint is clearly in the error message. The example framework for Ogre expects certain files to be available, such as resource.cfg and even plugins.cfg. Make sure this is in the path, and that the media required by those resources is also available.