00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00046 #include "PluginLoader.hpp"
00047 #include "../TaskContext.hpp"
00048 #include "../Logger.hpp"
00049 #include <boost/filesystem.hpp>
00050 #include <boost/version.hpp>
00051 #include "../os/StartStopManager.hpp"
00052 #include "../os/MutexLock.hpp"
00053 #include "../internal/GlobalService.hpp"
00054
00055 #include <cstdlib>
00056 #include <dlfcn.h>
00057
00058
00059 using namespace RTT;
00060 using namespace RTT::detail;
00061 using namespace plugin;
00062 using namespace std;
00063 using namespace boost::filesystem;
00064
00065
00066 #ifdef __APPLE__
00067 static const std::string SO_EXT(".dylib");
00068 static const std::string SO_POSTFIX("");
00069 #else
00070 # ifdef _WIN32
00071 static const std::string SO_EXT(".dll");
00072 # ifdef _DEBUG
00073 static const std::string SO_POSTFIX("d");
00074 # else
00075 static const std::string SO_POSTFIX("");
00076 # endif // _DEBUG
00077 # else
00078 static const std::string SO_EXT(".so");
00079 static const std::string SO_POSTFIX("");
00080 # endif
00081 #endif
00082
00083
00084 static const std::string FULL_PLUGINS_SUFFIX(string("-") + string(OROCOS_TARGET_NAME) + SO_POSTFIX + SO_EXT);
00085
00086
00087 # ifdef _WIN32
00088 static const std::string delimiters(";");
00089 static const std::string default_delimiter(";");
00090 # else
00091 static const std::string delimiters(":;");
00092 static const std::string default_delimiter(":");
00093 # endif
00094
00103 RTT_API bool isExtensionVersion(const std::string& ext)
00104 {
00105 bool isExtensionVersion = false;
00106
00107 if (!ext.empty() && ('.' == ext[0]))
00108 {
00109 std::istringstream iss;
00110 int i;
00111
00112 iss.str(ext.substr((size_t)1));
00113 iss >> std::dec >> std::noskipws >> i;
00114 isExtensionVersion = !iss.fail() && iss.eof();
00115 }
00116
00117 return isExtensionVersion;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 RTT_API bool isLoadableLibrary(const path& filename)
00142 {
00143 bool isLoadable = false;
00144
00145 #if defined(__APPLE__)
00146 std::string ext;
00147 ext = filename.extension().string();
00148
00149 if (0 == ext.compare(SO_EXT))
00150 {
00151
00152
00153
00154 path name = filename.stem();
00155 path ext = name.extension();
00156 isLoadable =
00157
00158 !name.empty() &&
00159
00160 (ext.empty() || !isExtensionVersion(ext.string()));
00161 }
00162
00163
00164 #else
00165
00166
00167
00168 isLoadable =
00169 (filename.extension() == SO_EXT) &&
00170 !filename.stem().empty();
00171 #endif
00172
00173 return isLoadable;
00174 }
00175
00176 namespace RTT { namespace plugin {
00177 extern char const* default_plugin_path;
00178 }}
00179
00180 namespace {
00184 int loadPlugins()
00185 {
00186 std::string default_plugin_path = ::default_plugin_path;
00187
00188 char* paths = getenv("RTT_COMPONENT_PATH");
00189 string plugin_paths;
00190 if (paths) {
00191 plugin_paths = paths;
00192
00193 if ( !default_plugin_path.empty() )
00194 plugin_paths = plugin_paths + default_delimiter + default_plugin_path;
00195 log(Info) <<"RTT_COMPONENT_PATH was set to: " << paths << " . Searching in: "<< plugin_paths<< endlog();
00196 } else {
00197 plugin_paths = default_plugin_path;
00198 log(Info) <<"No RTT_COMPONENT_PATH set. Using default: " << plugin_paths <<endlog();
00199 }
00200
00201 PluginLoader::Instance()->setPluginPath(plugin_paths);
00202
00203 try {
00204 PluginLoader::Instance()->loadPlugin("rtt", plugin_paths);
00205 PluginLoader::Instance()->loadTypekit("rtt", plugin_paths);
00206 } catch(std::exception& e) {
00207 log(Warning) << e.what() <<endlog();
00208 log(Warning) << "Corrupted files found in '" << plugin_paths << "'. Fix or remove these plugins."<<endlog();
00209 }
00210 return 0;
00211 }
00212
00213 os::InitFunction plugin_loader( &loadPlugins );
00214
00215 void unloadPlugins()
00216 {
00217 PluginLoader::Release();
00218 }
00219
00220 os::CleanupFunction plugin_unloader( &unloadPlugins );
00221 }
00222
00223 static boost::shared_ptr<PluginLoader> instance2;
00224
00225 namespace {
00226
00227 vector<string> splitPaths(string const& str)
00228 {
00229 vector<string> paths;
00230
00231
00232 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00233
00234 string::size_type pos = str.find_first_of(delimiters, lastPos);
00235
00236 while (string::npos != pos || string::npos != lastPos)
00237 {
00238
00239 if ( !str.substr(lastPos, pos - lastPos).empty() )
00240 paths.push_back(str.substr(lastPos, pos - lastPos));
00241
00242 lastPos = str.find_first_not_of(delimiters, pos);
00243
00244 pos = str.find_first_of(delimiters, lastPos);
00245 }
00246 if ( paths.empty() )
00247 paths.push_back(".");
00248 return paths;
00249 }
00250
00257 string makeShortFilename(string const& str) {
00258 string ret = str;
00259 if (str.substr(0,3) == "lib")
00260 ret = str.substr(3);
00261 if (ret.rfind(FULL_PLUGINS_SUFFIX) != string::npos)
00262 ret = ret.substr(0, ret.rfind(FULL_PLUGINS_SUFFIX) );
00263 return ret;
00264 }
00265
00266 }
00267
00268 bool hasEnding(string const &fullString, string const &ending)
00269 {
00270 if (fullString.length() > ending.length()) {
00271 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
00272 } else {
00273 return false;
00274 }
00275 }
00276
00277 PluginLoader::PluginLoader() { log(Debug) <<"PluginLoader Created" <<endlog(); }
00278 PluginLoader::~PluginLoader(){ log(Debug) <<"PluginLoader Destroyed" <<endlog(); }
00279
00280
00281 boost::shared_ptr<PluginLoader> PluginLoader::Instance() {
00282 if (!instance2) {
00283 instance2.reset( new PluginLoader() );
00284 }
00285 return instance2;
00286 }
00287
00288 void PluginLoader::Release() {
00289 instance2.reset();
00290 }
00291
00292 bool PluginLoader::loadTypekits(string const& path_list) {
00293 MutexLock lock( listlock );
00294 return loadPluginsInternal( path_list, "types", "typekit");
00295 }
00296
00297 bool PluginLoader::loadTypekit(std::string const& name, std::string const& path_list) {
00298 MutexLock lock( listlock );
00299 return loadPluginInternal(name, path_list, "types", "typekit");
00300 }
00301
00302 bool PluginLoader::loadPlugin(std::string const& name, std::string const& path_list) {
00303 MutexLock lock( listlock );
00304 return loadPluginInternal(name, path_list, "plugins", "plugin");
00305 }
00306
00307 bool PluginLoader::loadPlugins(string const& path_list) {
00308 MutexLock lock( listlock );
00309 return loadPluginsInternal( path_list, "plugins", "plugin");
00310 }
00311
00312 bool PluginLoader::loadService(string const& servicename, TaskContext* tc) {
00313 MutexLock lock( listlock );
00314 for(vector<LoadedLib>::iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00315 if (it->filename == servicename || it->plugname == servicename || it->shortname == servicename) {
00316 if (tc) {
00317 log(Info) << "Loading Service or Plugin " << servicename << " in TaskContext " << tc->getName() <<endlog();
00318 try {
00319 return it->loadPlugin( tc );
00320 } catch(std::exception& e) {
00321 log(Error) << "Service or Plugin "<< servicename <<" threw an exception during loading in " << tc->getName() << endlog();
00322 log(Error) << "Exception: "<< e.what() << endlog();
00323 return false;
00324 } catch(...) {
00325 log(Error) << "Service or Plugin "<< servicename <<" threw an unknown exception during loading in " << tc->getName() << endlog();
00326 return false;
00327 }
00328 } else {
00329
00330 if (it->is_service)
00331 try {
00332 return internal::GlobalService::Instance()->addService( it->createService() );
00333 } catch(std::exception& e) {
00334 log(Error) << "Service "<< servicename <<" threw an exception during loading in global service." << endlog();
00335 log(Error) << "Exception: "<< e.what() << endlog();
00336 return false;
00337 } catch(...) {
00338 log(Error) << "Service "<< servicename <<" threw an unknown exception during loading in global service. " << endlog();
00339 return false;
00340 }
00341 log(Error) << "Plugin "<< servicename << " was found, but it's not a Service." <<endlog();
00342 }
00343 }
00344 }
00345 log(Error) << "No such service or plugin: '"<< servicename << "'"<< endlog();
00346 return false;
00347 }
00348
00349
00350 bool PluginLoader::loadPluginsInternal( std::string const& path_list, std::string const& subdir, std::string const& kind )
00351 {
00352
00353 path arg( path_list );
00354 if (is_regular_file(arg)) {
00355 #if BOOST_VERSION >= 104600
00356 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind, true) == false)
00357 #else
00358 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind, true) == false)
00359 #endif
00360 throw std::runtime_error("The plugin "+path_list+" was found but could not be loaded !");
00361 log(Warning) << "You supplied a filename to 'loadPlugins(path)' or 'loadTypekits(path)'."<< nlog();
00362 log(Warning) << "Please use 'loadLibrary(filename)' instead since the function you use will only scan directories in future releases."<<endlog();
00363 return true;
00364 }
00365
00366
00367 vector<string> paths;
00368 if (path_list.empty())
00369 return false;
00370 else
00371 paths = splitPaths( path_list );
00372
00373 bool all_good = true, found = false;
00374
00375 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00376 {
00377
00378 path p = path(*it) / subdir;
00379 if (is_directory(p))
00380 {
00381 log(Info) << "Loading "<<kind<<" libraries from directory " << p.string() << " ..."<<endlog();
00382 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00383 {
00384 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00385 if (is_regular_file(itr->status()) && isLoadableLibrary(itr->path()) ) {
00386 found = true;
00387 std::string libname;
00388 #if BOOST_VERSION >= 104600
00389 libname = itr->path().filename().string();
00390 #else
00391 libname = itr->path().filename();
00392 #endif
00393 if(!isCompatiblePlugin(libname))
00394 {
00395 log(Debug) << "not a compatible plugin: ignored."<<endlog();
00396 }
00397 else
00398 {
00399 found = true;
00400 all_good = loadInProcess( itr->path().string(), makeShortFilename(libname), kind, true) && all_good;
00401 }
00402 } else {
00403 if (!is_regular_file(itr->status()))
00404 log(Debug) << "not a regular file: ignored."<<endlog();
00405 else
00406 log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00407 }
00408 }
00409 }
00410 else
00411 log(Debug) << "No such directory: " << p << endlog();
00412 }
00413 if (!all_good)
00414 throw std::runtime_error("Some found plugins could not be loaded !");
00415 return found;
00416 }
00417
00418 bool PluginLoader::loadLibrary( std::string const& name )
00419 {
00420
00421 path arg( name );
00422 if (is_regular_file(arg)) {
00423 #if BOOST_VERSION >= 104600
00424 string subdir = arg.parent_path().filename().string();
00425 #else
00426 string subdir = arg.parent_path().leaf();
00427 #endif
00428 string kind;
00429
00430 if (subdir == "types") kind = "typekit";
00431 if (subdir == "plugins") kind = "plugin";
00432 if ( !kind.empty() ) {
00433 #if BOOST_VERSION >= 104600
00434 string libname = arg.filename().string();
00435 #else
00436 string libname = arg.filename();
00437 #endif
00438 if(!isCompatiblePlugin(libname))
00439 {
00440 log(Error) << "The " << kind << " " << name << " was found but is incompatible." << endlog();
00441 return false;
00442 }
00443
00444 #if BOOST_VERSION >= 104600
00445 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename().string()), kind, true) == false)
00446 #else
00447 if ( loadInProcess(arg.string(), makeShortFilename(arg.filename()), kind, true) == false)
00448 #endif
00449 throw std::runtime_error("The plugin "+name+" was found but could not be loaded !");
00450 return true;
00451 }
00452
00453 log(Error) << "refusing to load " << name << " as I could not autodetect its type (name=" << name << ", path=" << arg.string() << ", subdir=" << subdir << ")" << endlog();
00454
00455 return false;
00456 }
00457
00458
00459 if ( arg.is_complete() )
00460 return false;
00461
00462
00463 path dir = arg.parent_path();
00464 #if BOOST_VERSION >= 104600
00465 string file = arg.filename().string();
00466 #else
00467 string file = arg.filename();
00468 #endif
00469 vector<string> paths = splitPaths(plugin_path);
00470 vector<string> tryouts( paths.size() * 8 );
00471 tryouts.clear();
00472
00473
00474 string subdir = "plugins"; string kind = "plugin";
00475 while (true) {
00476 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00477 {
00478 path p = path(*it) / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
00479 tryouts.push_back( p.string() );
00480 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00481 return true;
00482 p = path(*it) / dir / subdir / ("lib" + file + FULL_PLUGINS_SUFFIX);
00483 tryouts.push_back( p.string() );
00484 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00485 return true;
00486 p = path(*it) / OROCOS_TARGET_NAME / dir / subdir / (file + FULL_PLUGINS_SUFFIX);
00487 tryouts.push_back( p.string() );
00488 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00489 return true;
00490 p = path(*it) / OROCOS_TARGET_NAME / dir / subdir / ("lib" + file + FULL_PLUGINS_SUFFIX);
00491 tryouts.push_back( p.string() );
00492 if (is_regular_file( p ) && loadInProcess( p.string(), name, kind, true ) )
00493 return true;
00494 }
00495 if (subdir == "types")
00496 break;
00497 subdir = "types";
00498 kind = "typekit";
00499 }
00500 log(Debug) << "No such "<< kind << " found in path: " << name << ". Tried:"<< endlog();
00501 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
00502 log(Debug) << *it << endlog();
00503
00504 return false;
00505 }
00506
00507 bool PluginLoader::loadPluginInternal( std::string const& name, std::string const& path_list, std::string const& subdir, std::string const& kind )
00508 {
00509
00510
00511 if (name != "rtt" && loadLibrary(name)) {
00512 log(Warning) << "You supplied a filename as first argument to 'loadPlugin(name,path)' or 'loadTypekit(name,path)'."<<nlog();
00513 log(Warning) << "Please use 'loadLibrary(filename)' instead since the function you use will only interprete 'name' as a directory name in future releases."<<endlog();
00514 return true;
00515 }
00516
00517 if ( isLoadedInternal(name) ) {
00518 log(Debug) <<kind << " '"<< name <<"' already loaded. Not reloading it." <<endlog();
00519 return true;
00520 } else {
00521 log(Info) << kind << " '"<< name <<"' not loaded before." <<endlog();
00522 }
00523
00524 string paths, trypaths;
00525 if (path_list.empty())
00526 paths = plugin_path + default_delimiter + ".";
00527 else
00528 paths = path_list;
00529
00530
00531 if (paths.empty())
00532 paths = ".";
00533
00534
00535 vector<string> vpaths = splitPaths(paths);
00536 paths.clear();
00537 bool path_found = false;
00538 string plugin_dir = name;
00539 if (name == "rtt" )
00540 plugin_dir = ".";
00541 for(vector<string>::iterator it = vpaths.begin(); it != vpaths.end(); ++it) {
00542 path p(*it);
00543 p = p / plugin_dir;
00544
00545 if (is_directory( p )) {
00546 path_found = true;
00547 paths += p.string() + default_delimiter;
00548 } else {
00549 trypaths += p.string() + default_delimiter;
00550 }
00551 p = *it;
00552 p = p / OROCOS_TARGET_NAME / plugin_dir;
00553
00554 if (is_directory( p )) {
00555 path_found = true;
00556 paths += p.string() + default_delimiter;
00557 } else {
00558 trypaths += p.string() + default_delimiter;
00559 }
00560 }
00561
00562
00563 if (path_found) {
00564 paths.erase( paths.size() - 1 );
00565 return loadPluginsInternal(paths,subdir,kind);
00566 }
00567 log(Error) << "No such "<< kind << " found in path: " << name << ". Looked for these directories: "<< endlog();
00568 if ( !paths.empty() )
00569 log(Error) << "Exist, but don't contain it: " << paths << endlog();
00570 else
00571 log(Error) << "None of the search paths exist !" << endlog();
00572 if ( !trypaths.empty() )
00573 log(Error) << "Don't exist: " << trypaths << endlog();
00574 return false;
00575 }
00576
00577 bool PluginLoader::isLoaded(string file)
00578 {
00579 MutexLock lock( listlock );
00580 return isLoadedInternal(file);
00581 }
00582
00583 bool PluginLoader::isLoadedInternal(string file)
00584 {
00585 path p(file);
00586 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
00587 while (lib != loadedLibs.end()) {
00588
00589 if ( lib->filename == p.filename() || lib->plugname == file || lib->shortname == file ) {
00590 return true;
00591 }
00592 ++lib;
00593 }
00594 return false;
00595 }
00596
00597
00598 bool PluginLoader::loadInProcess(string file, string shortname, string kind, bool log_error) {
00599 path p(file);
00600 char* error;
00601 void* handle;
00602
00603 if ( isLoadedInternal(shortname) || isLoadedInternal(file) ) {
00604 log(Debug) <<"plugin '"<< file <<"' already loaded. Not reloading it." <<endlog() ;
00605 return true;
00606 }
00607
00608
00609 if(!isCompatiblePlugin(file))
00610 {
00611 if(log_error)
00612 log(Error) << "could not load library '"<< p.string() <<"': incompatible." <<endlog();
00613 return false;
00614 }
00615
00616 handle = dlopen ( p.string().c_str(), RTLD_NOW | RTLD_GLOBAL );
00617
00618 if (!handle) {
00619 string e( dlerror() );
00620 if (log_error)
00621 log(Error) << "could not load library '"<< p.string() <<"': "<< e <<endlog();
00622 else
00623 endlog();
00624 return false;
00625 }
00626
00627
00628 #if BOOST_VERSION >= 104600
00629 string libname = p.filename().string();
00630 #else
00631 string libname = p.filename();
00632 #endif
00633 log(Debug)<<"Found library "<<libname<<endlog();
00634 LoadedLib loading_lib(libname,shortname,handle);
00635 dlerror();
00636
00637 std::string(*pluginName)(void) = 0;
00638 std::string(*targetName)(void) = 0;
00639 loading_lib.loadPlugin = (bool(*)(RTT::TaskContext*))(dlsym(handle, "loadRTTPlugin") );
00640 if ((error = dlerror()) == NULL) {
00641 string plugname, targetname;
00642 pluginName = (std::string(*)(void))(dlsym(handle, "getRTTPluginName") );
00643 if ((error = dlerror()) == NULL) {
00644 plugname = (*pluginName)();
00645 } else {
00646 plugname = libname;
00647 }
00648 loading_lib.plugname = plugname;
00649 targetName = (std::string(*)(void))(dlsym(handle, "getRTTTargetName") );
00650 if ((error = dlerror()) == NULL) {
00651 targetname = (*targetName)();
00652 } else {
00653 targetname = OROCOS_TARGET_NAME;
00654 }
00655 if ( targetname != OROCOS_TARGET_NAME ) {
00656 log(Error) << "Plugin "<< plugname <<" reports to be compiled for OROCOS_TARGET "<< targetname
00657 << " while we are running on target "<< OROCOS_TARGET_NAME <<". Unloading."<<endlog();
00658 dlclose(handle);
00659 return false;
00660 }
00661
00662
00663 loading_lib.createService = (Service::shared_ptr(*)(void))(dlsym(handle, "createService") );
00664 if (loading_lib.createService)
00665 loading_lib.is_service = true;
00666
00667
00668 bool success = false;
00669 try {
00670
00671 success = (*loading_lib.loadPlugin)( 0 );
00672 } catch(...) {
00673 log(Error) << "Unexpected exception in loadRTTPlugin !"<<endlog();
00674 }
00675
00676 if ( !success ) {
00677 log(Error) << "Failed to load RTT Plugin '" <<plugname<<"': plugin refused to load into this process. Unloading." <<endlog();
00678 dlclose(handle);
00679 return false;
00680 }
00681 if (kind == "typekit") {
00682 log(Info) << "Loaded RTT TypeKit/Transport '" + plugname + "' from '" + shortname +"'"<<endlog();
00683 loading_lib.is_typekit = true;
00684 } else {
00685 loading_lib.is_typekit = false;
00686 if ( loading_lib.is_service ) {
00687 log(Info) << "Loaded RTT Service '" + plugname + "' from '" + shortname +"'"<<endlog();
00688 }
00689 else {
00690 log(Info) << "Loaded RTT Plugin '" + plugname + "' from '" + shortname +"'"<<endlog();
00691 }
00692 }
00693 loadedLibs.push_back(loading_lib);
00694 return true;
00695 } else {
00696 if (log_error)
00697 log(Error) <<"Not a plugin: " << error << endlog();
00698 }
00699 dlclose(handle);
00700 return false;
00701 }
00702
00703 std::vector<std::string> PluginLoader::listServices() const {
00704 MutexLock lock( listlock );
00705 vector<string> names;
00706 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00707 if ( it->is_service )
00708 names.push_back( it->plugname );
00709 }
00710 return names;
00711 }
00712
00713 std::vector<std::string> PluginLoader::listPlugins() const {
00714 MutexLock lock( listlock );
00715 vector<string> names;
00716 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00717 names.push_back( it->plugname );
00718 }
00719 return names;
00720 }
00721
00722 std::vector<std::string> PluginLoader::listTypekits() const {
00723 MutexLock lock( listlock );
00724 vector<string> names;
00725 for(vector<LoadedLib>::const_iterator it= loadedLibs.begin(); it != loadedLibs.end(); ++it) {
00726 if ( it->is_typekit )
00727 names.push_back( it->plugname );
00728 }
00729 return names;
00730 }
00731
00732 std::string PluginLoader::getPluginPath() const {
00733 MutexLock lock( listlock );
00734 return plugin_path;
00735 }
00736
00737 void PluginLoader::setPluginPath( std::string const& newpath ) {
00738 MutexLock lock( listlock );
00739 plugin_path = newpath;
00740 }
00741
00742 bool PluginLoader::isCompatiblePlugin(std::string const& filepath)
00743 {
00744 path p(filepath);
00745
00746 #if BOOST_VERSION >= 104600
00747 string libname = p.filename().string();
00748 #else
00749 string libname = p.filename();
00750 #endif
00751
00752
00753
00754 #ifdef OROCOS_TARGET_WIN32
00755
00756
00757
00758 if(!hasEnding(libname, FULL_PLUGINS_SUFFIX))
00759 {
00760
00761 return false;
00762 }
00763 #endif // OROCOS_TARGET_WIN32
00764
00765
00766
00767
00768
00769 return true;
00770 }