Dylib.cpp 7.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
//    Copyright (c) 1997-2000 Mark Danks.
zmoelnig's avatar
zmoelnig committed
10
//    Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
11
12
13
14
15
16
17
18
19
//    Copyright (c) 2002 James Tittle & Chris Clepper
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
// a wrapper for calling Pd's sys_register_loader()
//
/////////////////////////////////////////////////////////
#ifdef _MSC_VER
# pragma warning( disable: 4091)
20
# define snprintf _snprintf
21
22
#endif /* _MSC_VER */

zmoelnig's avatar
zmoelnig committed
23
#include "Dylib.h"
24
#include "Files.h"
zmoelnig's avatar
zmoelnig committed
25
#include "Base/CPPExtern.h"
26
27

#include <string>
28
#include <algorithm>
29

30
#if defined __linux__ || defined __APPLE__ || defined __FreeBSD_kernel__
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
31
# include <unistd.h>
32
33
34
35
36
37
38
39
40
41
42
43
# define DL_OPEN
#endif

#ifdef DL_OPEN
# include <dlfcn.h>
#endif

#if defined _WIN32
# include <io.h>
# include <windows.h>
#endif

44
#include <iostream>
45

46
47
static std::vector<GemDylib*>s_dylibs;

48
49
class GemDylibHandle {
public:
50
  std::string fullname;
51
#ifdef DL_OPEN
zmoelnig's avatar
zmoelnig committed
52
  void * dlhandle;
53
#endif
zmoelnig's avatar
zmoelnig committed
54
55
56
57
#ifdef _WIN32
  HINSTANCE w32handle;
#endif
  int dummy2;
58

59
60

  GemDylibHandle(void) :
61
    fullname(std::string()),
zmoelnig's avatar
zmoelnig committed
62
63
64
65
66
67
68
69
#ifdef DL_OPEN
    dlhandle(NULL),
#endif
#ifdef _WIN32
    w32handle(NULL),
#endif
    dummy2(0)
  {;}
zmoelnig's avatar
zmoelnig committed
70

71
72
73
74
  ~GemDylibHandle(void) {
    close();
  }

zmoelnig's avatar
zmoelnig committed
75
  static std::string getFullfilename(const t_canvas*canvas, const char*filename, const char*ext) {
76
    std::string fullname_;
zmoelnig's avatar
zmoelnig committed
77
78
79
80
81

    char buf[MAXPDSTRING];
    char*bufptr;
    int fd=0;
    if ((fd=canvas_open(const_cast<t_canvas*>(canvas), filename, ext, buf, &bufptr, MAXPDSTRING, 1))>=0){
82
      gem::files::close(fd);
83
84
85
      fullname_=buf;
      fullname_+="/";
      fullname_+=bufptr;
zmoelnig's avatar
zmoelnig committed
86
87
88
    } else {
      if(canvas) {
        canvas_makefilename(const_cast<t_canvas*>(canvas), const_cast<char*>(filename), buf, MAXPDSTRING);
89
        fullname_=buf;
zmoelnig's avatar
zmoelnig committed
90
91
92
93
      } else {
        return std::string("");
      }
    }
94
    return fullname_;
zmoelnig's avatar
zmoelnig committed
95
96
  }

97
  static GemDylibHandle*open(const std::string&filename) {
zmoelnig's avatar
zmoelnig committed
98
99
    GemDylibHandle*handle=new GemDylibHandle();

100
101
    if(filename.empty()) {
      throw(GemException(std::string("No DyLib name given!")));
zmoelnig's avatar
zmoelnig committed
102
103
104
    }

#ifdef DL_OPEN
105
106
107
    handle->dlhandle=dlopen(filename.c_str(), RTLD_NOW);
    if(handle->dlhandle) {
      handle->fullname=filename;
zmoelnig's avatar
zmoelnig committed
108
      return handle;
109
    }
zmoelnig's avatar
zmoelnig committed
110
111
#endif
#ifdef _WIN32
112
113
    char buf[MAXPDSTRING];
    sys_bashfilename(filename.c_str(), buf);
zmoelnig's avatar
zmoelnig committed
114
    UINT errorboxflags=SetErrorMode(SEM_FAILCRITICALERRORS);
115
	SetLastError(0);
zmoelnig's avatar
zmoelnig committed
116
    handle->w32handle=LoadLibrary(buf);
117
	DWORD errorNumber = GetLastError();
zmoelnig's avatar
zmoelnig committed
118
    errorboxflags=SetErrorMode(errorboxflags);
119
120
    if(handle->w32handle) {
      handle->fullname=filename;
zmoelnig's avatar
zmoelnig committed
121
      return handle;
122
    }
zmoelnig's avatar
zmoelnig committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#endif

    delete handle;
    handle=NULL;

    std::string errormsg;
#ifdef DL_OPEN
    errormsg=dlerror();
    if(!errormsg.empty()) {
      std::string error="dlerror '";
      error+=errormsg;
      error+="'";
      throw(GemException(error));
    }
#endif
#ifdef _WIN32
139
140
141
    LPVOID lpErrorMessage=NULL;
	if(errorNumber) {
		FormatMessage(
142
                  FORMAT_MESSAGE_ALLOCATE_BUFFER |
zmoelnig's avatar
zmoelnig committed
143
144
145
146
147
148
                  FORMAT_MESSAGE_FROM_SYSTEM,
                  NULL,
                  errorNumber,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR) &lpErrorMessage,
                  0, NULL );
149
150
151
152
153
154
155
156
157
	}
	std::cerr << "GemDylib failed: #"<<errorNumber<<": ";
	if(lpErrorMessage) {
		std::cerr<<(const char*)lpErrorMessage;
	}else {
		std::cerr<<"(unknown)";
	}
	std::cerr<<std::endl;
    std::string error = "DLLerror(";
158
    char errbuf[10];
159
    snprintf(errbuf, 10, "0x%x", errorNumber);
160
161
    errbuf[10-1]=0;
    error+=errbuf;
162
163
164
165
166
167
	error+=")";
	if(lpErrorMessage) {
		error+=(const char*)lpErrorMessage;
	}
	std::cerr << "GemDylib throwing: "<< error << std::endl;
	throw(GemException(std::string(error)));
zmoelnig's avatar
zmoelnig committed
168
#endif
169

zmoelnig's avatar
zmoelnig committed
170
171
    return NULL;
  }
172

173
  static GemDylibHandle*open(const CPPExtern*obj, const std::string&filename, const std::string&extension) {
174
    //const t_canvas*canvas=(obj)?(const_cast<CPPExtern*>(obj)->getCanvas()):0;
175
176
    const char*ext=extension.c_str();

177
178
    //std::string fullname=getFullfilename(canvas, filename.c_str(), ext);
    std::string fullname=gem::files::getFullpath(filename+ext, obj);
179
    if(fullname.empty()) {
180
181
      //fullname=getFullfilename(canvas, filename.c_str(), GemDylibHandle::defaultExtension.c_str());
      fullname=gem::files::getFullpath(filename+GemDylibHandle::defaultExtension, obj);
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    }

    if(fullname.empty()) {
      std::string error="couldn't find '";
      error+=filename;
      error+="'.'";
      error+=ext;
      error+="'";
      throw(GemException(error));
    }

    return open(fullname);
  }

zmoelnig's avatar
zmoelnig committed
196
197
  static const std::string defaultExtension;

198
199
200
201
202
203
204
205
206
207
208
209
210
  void close(void) {
#ifdef DL_OPEN
    if(dlhandle)
      dlclose(dlhandle);
    dlhandle=NULL;
#endif
#ifdef _WIN32
    if(w32handle)
      FreeLibrary(w32handle);
    w32handle=NULL;
#endif
  }

211
212
};

213
const std::string GemDylibHandle::defaultExtension =
zmoelnig's avatar
zmoelnig committed
214
215
216
217
218
219
220
221
222
223
#ifdef _WIN32
                               std::string(".dll")
#elif defined DL_OPEN
                               std::string(".so")
#else
                               std::string("")
#endif
  ;


224
GemDylib::GemDylib(const CPPExtern*obj, const std::string&filename, const std::string&extension)
225
  : m_handle(0) {
zmoelnig's avatar
zmoelnig committed
226
    m_handle=GemDylibHandle::open(obj, filename, extension);
227
228
229
230
    if(NULL==m_handle) {
      std::string err="unable to open '";
      err+=filename;
      if(!extension.empty()) {
zmoelnig's avatar
zmoelnig committed
231
232
        err+=".";
        err+=extension;
233
234
235
      }
      err+="'";
      throw GemException(err);
236
    }
237
238
    s_dylibs.push_back(this);
}
239

240
GemDylib::GemDylib(const std::string&filename, const std::string&extension)
241
  : m_handle(0) {
242
243
244
  m_handle=GemDylibHandle::open(filename+extension);
  if(NULL==m_handle)
    m_handle=GemDylibHandle::open(filename+GemDylibHandle::defaultExtension);
245
  if(NULL==m_handle) {
246
    std::string err="unable to open '";
247
    err+=filename;
248
    if(!extension.empty()) {
249
250
251
252
253
254
      err+=".";
      err+=extension;
    }
    err+="'";
    throw GemException(err);
  }
255
  s_dylibs.push_back(this);
256
257
}

258

259
260
261
262
263
264
265
266
267
GemDylib::GemDylib(const GemDylib&org) : m_handle(NULL) {
  std::string filename=org.m_handle->fullname;
  m_handle=GemDylibHandle::open(filename);
  if(NULL==m_handle) {
    std::string err="unable to open '";
    err+=filename;
    err+="'";
    throw GemException(err);
  }
268
  s_dylibs.push_back(this);
269
}
270
271

GemDylib::~GemDylib(void) {
272
273
274
  if(m_handle)
    delete m_handle;
  m_handle=NULL;
275

276
  s_dylibs.erase( std::remove(s_dylibs.begin(), s_dylibs.end(), this), s_dylibs.end() );
277
278
}

279
GemDylib& GemDylib::operator=(const GemDylib&org) {
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
280
281
  if(&org == this)
    return *this;
282
283
284
285
286
287
  if(m_handle)
    delete m_handle;
  m_handle=NULL;
  if(org.m_handle) {
    m_handle=GemDylibHandle::open(org.m_handle->fullname);
  }
zmoelnig's avatar
zmoelnig committed
288
  return *this;
289
290
291
}


292
GemDylib::function_t GemDylib::proc(const std::string&procname) {
zmoelnig's avatar
zmoelnig committed
293
  function_t result=NULL;
294
295
296
  //  if(NULL==procname)return NULL;
#ifdef DL_OPEN
  dlerror();
zmoelnig's avatar
zmoelnig committed
297
  if(m_handle->dlhandle)
zmoelnig's avatar
zmoelnig committed
298
    result=(function_t)(dlsym(m_handle->dlhandle, procname.c_str()));
zmoelnig's avatar
zmoelnig committed
299
300
301
302
  if(NULL!=result)return result;
#endif
#ifdef _WIN32
  if(m_handle->w32handle)
zmoelnig's avatar
zmoelnig committed
303
    result=(function_t)(GetProcAddress(m_handle->w32handle, procname.c_str()));
zmoelnig's avatar
zmoelnig committed
304
  if(NULL!=result)return result;
305
306
#endif

zmoelnig's avatar
zmoelnig committed
307
  return result;
308
309
}

310
bool GemDylib::run(const std::string&procname) {
zmoelnig's avatar
zmoelnig committed
311
  function_t runproc=proc(procname);
312
  if(runproc) {
zmoelnig's avatar
zmoelnig committed
313
    (runproc)();
314
315
316
317
318
    return true;
  }
  return false;
}

319
bool GemDylib::LoadLib(const std::string&basefilename, const std::string&extension, const std::string&procname) {
zmoelnig's avatar
zmoelnig committed
320
321
322
323
324
325
326
327
328
329
  try {
    GemDylib*dylib=new GemDylib(basefilename, extension);
    if(NULL!=dylib) {
      dylib->run(procname);
      return true;
    }
  } catch (GemException&x) {
    std::cerr << "GemDylib::LoadLib: "<<x.what()<<std::endl;
  }

330
331
332
333
  return false;
}


zmoelnig's avatar
zmoelnig committed
334
const std::string GemDylib::getDefaultExtension(void) {
zmoelnig's avatar
zmoelnig committed
335
  return GemDylibHandle::defaultExtension;
336
}