diff --git a/include/applicat.cpp b/include/applicat.cpp index d11968ca0..28c11fa90 100755 --- a/include/applicat.cpp +++ b/include/applicat.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,13 +26,14 @@ #include -#define BITTEST(w,p) (((w) & (0x0001 << (p))) != 0) +// #define BITTEST(w,p) (((w) & (0x0001 << (p))) != 0) /////////////////////////////////////////////////////////// // Metodi di accesso globali all'applicazione corrente /////////////////////////////////////////////////////////// HIDDEN TApplication* _application = NULL; +HIDDEN BOOL _xvt_running = FALSE; // @doc EXTERNAL @@ -53,7 +55,7 @@ TApplication& main_app() // @flag TRUE | Se se e' stata definita una // @flag FALSE | Se se non e' stata definita una bool xvt_running() -{ return _application != NULL; } +{ return _xvt_running; } // Ritorna il nome della ditta che vende il programma attuale HIDDEN char* prassi_spa() @@ -410,7 +412,8 @@ bool TApplication::remove_menu(MENU_TAG id) TApplication::TApplication() : _savefirm(0), _create_ok(FALSE) -{} +{ +} TApplication::~TApplication() @@ -482,19 +485,22 @@ const char* TApplication::get_module_name() const if (!ok) { TToken_string em(extra_modules()); - if (em != "*") + if (!em.empty_items()) { - FOR_EACH_TOKEN(em, cod) + if (em != "*") { - if (has_module(atoi(cod))) + FOR_EACH_TOKEN(em, cod) { - ok = TRUE; - break; - } + if (has_module(atoi(cod))) + { + ok = TRUE; + break; + } + } } - } - else - ok = TRUE; + else + ok = TRUE; + } if (!ok) { error_box("Il modulo '%s' non e' autorizzato", (const char*)module); @@ -512,8 +518,7 @@ void TApplication::set_perms() _dongle_aut.set(0, TRUE); for (int i = 1 ; i < ENDAUT; i++) { - const int af = i - 1; - const bool val = BITTEST(_int_tab0[af / 16], af % 16); + const bool val = dongle().active(i); _dongle_aut.set(i, val); } #endif @@ -579,6 +584,10 @@ void TApplication::run( // @comm E' in questa fase che si controlla se esiste la chiave e' attaccata { + CHECK(_application == NULL, "Sorry, multitasking not implemented"); + // Devo metterla qui per far funzionare la TDongle::network_login + _application = this; + TFilename base(argv[0]); base.ext(""); base.lower(); @@ -604,7 +613,8 @@ void TApplication::run( else CGetPref(); - const int sn = get_serial_number(firm_change_enabled() ? _name : "ba0100"); + const int sn = get_serial_number(); + if (sn < 0) { error_box("Probabilmente non e' stata inserita la chiave di protezione"); @@ -631,7 +641,7 @@ void TApplication::run( set_xvt_hooks(); - _application = this; + _xvt_running = TRUE; xvt_app_create(argc, argv, 0L, task_eh, &cfg); } @@ -654,18 +664,19 @@ bool TApplication::get_version_info(int& year, int& release, int& tag, int& patc void TApplication::about() const { const TFilename n(__argv[0]); - + const word ser_no = dongle().number(); int year, release, tag, patch; + if (get_version_info(year, release, tag, patch)) { - message_box("Versione %d.%02d\nProgramma %s\nN.ro di serie %d-%02d.%03d", - year, release, (const char*)n.name(), SerNo, tag, patch); + message_box("Versione %d.%02d\nProgramma %s\nN.ro di serie %u-%02d.%03d", + year, release, (const char*)n.name(), ser_no, tag, patch); } else { #include - message_box("Versione %s\nProgramma %s\nLibreria del %s\nN.ro di serie %d-%s", - VERSION, (const char*)n.name(), __DATE__, SerNo, INTERNAL_VERSION); + message_box("Versione %s\nProgramma %s\nLibreria del %s\nN.ro di serie %u-%s", + VERSION, (const char*)n.name(), __DATE__, ser_no, INTERNAL_VERSION); } } diff --git a/include/browfile.h b/include/browfile.h index db0fb03c9..afa021ce3 100755 --- a/include/browfile.h +++ b/include/browfile.h @@ -14,29 +14,22 @@ class TViswin; // dal testo ritornato typedef const char* (*MASK_LINKHANDLER)(TMask&, int, const char*, bool doubleclick); -class TBrowsefile_field : public TOperable_field +class TBrowsefile_field : public TWindowed_field { friend class TViswin; - TViswin* _viswin; MASK_LINKHANDLER _lh; TArray _links; bool _m_link; - short _dlg; - WINDOW _parent; TString_array _background; // Background per usi diversi da anteprima! protected: virtual word class_id() const; - - virtual void parse_head(TScanner& scanner); - virtual void create(WINDOW parent); + virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent); public: - - TViswin* vis_win() const { return _viswin; } - void set_vis_win(TViswin* viswin); + TViswin& vis_win() const { return (TViswin&)win(); } void add_line(const char* l); long set_text(const char* file, const char* line = NULL); @@ -66,10 +59,6 @@ public: void set_background(const char* bg); TString_array& get_bg_desc() { return _background; } - virtual short dlg() const { return _dlg; } - // @cmember Ritorna la finestra padre - virtual WINDOW parent() const { return _parent; } - TBrowsefile_field(TMask* m); virtual ~TBrowsefile_field(); }; diff --git a/include/dongle.cpp b/include/dongle.cpp new file mode 100755 index 000000000..7a7b36bfa --- /dev/null +++ b/include/dongle.cpp @@ -0,0 +1,683 @@ +#include + +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////// +// Hardlock stuff +/////////////////////////////////////////////////////////// + +#ifndef _DEMO_ + +#include + +#define USERADR 26952 +#define AGAADR 26953 +#define PRASSIADR 26954 +#define PROCOMADR 26956 +#define REFKEY "CAMPOKEY" +#define VERKEY "ìpÙˆ¬cê<" + +#endif + +/////////////////////////////////////////////////////////// +// Smartkey stuff +/////////////////////////////////////////////////////////// + +#ifndef _DEMO_ + +#define PANDLL +extern "C" +{ +#include "skeytsr.h" +} + +HIDDEN KEY_NET* _eutron_key = NULL; + +struct TEutronHeader +{ + char _serno[8]; + unsigned short _year_assist; + unsigned short _max_users; + unsigned long _last_date; + unsigned long _scad_date; + unsigned long _checksum; // Must be the last item! +}; + +#endif // _DEMO_ + +/////////////////////////////////////////////////////////// +// Current dongle +/////////////////////////////////////////////////////////// + +static TDongle* _dongle = NULL; + +TDongle& dongle() +{ + if (_dongle == NULL) + _dongle = new TDongle; + return *_dongle; +} + +bool destroy_dongle() +{ + bool ok = _dongle != NULL; + if (ok) + { + delete _dongle; + _dongle = NULL; + + if (_eutron_key) + { + delete _eutron_key; + _eutron_key = NULL; + } + } + return ok; +} + +/////////////////////////////////////////////////////////// +// Bit helper functions +/////////////////////////////////////////////////////////// + +inline bool test_bit(word w, int b) +{ + bool on = (w & (1 << b)) != 0; + return on; +} + +inline void set_bit(word& w, int b, bool on = TRUE) +{ + if (on) + w |= 1 << b; + else + w &= ~(1 << b); +} + +inline void reset_bit(word& w, byte b) +{ + w &= ~(1 << b); +} + +/////////////////////////////////////////////////////////// +// TDongle +/////////////////////////////////////////////////////////// + +TDongle::TDongle() + : _hardware(_dongle_unknown), _type(_no_dongle), _serno(0xFFFF), + _dirty(FALSE), _max_users(1), _year_assist(1997) +{ + memset(_eprom, 0, sizeof(_eprom)); +} + +TDongle::~TDongle() +{ + if (_serno != 0xFFFF) + logout(); +} + +// Data punta ad un array di 4 words +// Deve essere cosi' per problemi del C, +// non trasformare in array: pena di morte! +void TDongle::garble(word* data) const +{ +#ifndef _DEMO_ + switch (_hardware) + { + case _dongle_hardlock: + HL_CODE(EYECAST data, 1); + break; + case _dongle_eutron: + if (_eutron_key) + { + _eutron_key->net_command = NET_KEY_ACCESS; + _eutron_key->command = SCRAMBLING_MODE; + memcpy(_eutron_key->data, data, 8); + smartlink(_eutron_key); + if (_eutron_key->status == ST_OK) + memcpy(data, _eutron_key->data, 8); + else + NFCHECK("EUTRON scrambling error: %d", _eutron_key->status); + } + break; + default: + break; + } +#endif +} + +bool TDongle::already_programmed() const +{ +#ifndef _DEMO_ + if (_hardware == _dongle_hardlock) + { + word data[4]; + memcpy(data, &_eprom[60], sizeof(data)); + garble(data); + + if (data[0] < 1997 || data[0] > 2997) + return FALSE; + + if (data[1] == 0 || data[1] >= 10000) + return FALSE; + + const TDate today(TODAY); + const long& giulio = (const long&)data[2]; + const long yyyymmdd = today.julian2date(giulio); + const TDate d(yyyymmdd); + if (d.year() < 1997 || d > today) + return FALSE; + } else + if (_hardware == _dongle_eutron) + { + const TEutronHeader* eh = (const TEutronHeader*)_eprom; + if (eh->_serno[0] == 0 || eh->_checksum == 0) + return FALSE; // Really virgin. + + unsigned long cs = 0; + for (byte* ptr = (byte*)_eprom; ptr < (byte*)&eh->_checksum; ptr++) + cs += *ptr | ~(*ptr << 8); + if (eh->_checksum != cs) + return FALSE; // Malicious programming! + } +#endif // _DEMO_ + return TRUE; +} + +#ifndef _DEMO_ + +bool TDongle::hardlock_login(bool test_all_keys) +{ + bool ok = TRUE; + _type = _user_dongle; + if (test_all_keys) + { + HL_LOGOUT(); + if (HL_LOGIN(AGAADR, DONT_CARE, REFKEY, VERKEY) == STATUS_OK) + _type = _aga_dongle; + else + { + HL_LOGOUT(); + if (HL_LOGIN(PRASSIADR, DONT_CARE, REFKEY, VERKEY) == STATUS_OK) + _type = _prassi_dongle; + else + { + HL_LOGOUT(); + if (HL_LOGIN(PROCOMADR, DONT_CARE, REFKEY, VERKEY) == STATUS_OK) + _type = _procom_dongle; + } + } + } + HL_LOGOUT(); + ok = HL_LOGIN(USERADR, DONT_CARE, REFKEY, VERKEY) == STATUS_OK; + + if (ok) + { + _hardware = _dongle_hardlock; + + HL_READBL((char*)_eprom); + + word data[4]; + memcpy(data, _eprom, sizeof(data)); + garble(data); + + if (data[0] == 0xFAE8) + _serno = data[1]; + else + { + if (data[0] == 0x3283) // chiave programmatori !! + { + _type = _developer_dongle; + _serno = 0; + } + } + } + + if (ok) + { + _max_users = 1; + _last_update = TDate(TODAY); + _year_assist = _last_update.year(); + + if (_type == _user_dongle) + { + const bool already = already_programmed(); + + _module.reset(); + _module.set(0, TRUE); + const int last_word = already ? 12 : 4; + word data[4]; + + // Legge flag di attivazione dei moduli + for (int i = 0; i < last_word; i += 4) + { + memcpy(data, &_eprom[48+i], sizeof(data)); + garble(data); + if (data[3] == _serno) // Validate block + { + for (int j = 0; j < 3; j++) + { + word parola = data[j] ^ _serno; + if (parola) + { + for (int b = 15; b >= 0; b--) + { + if (test_bit(parola, b)) + { + const word bit = i * 12 + j * 16 + b; + _module.set(bit+1); + } + } + } + } + } + else + break; + } + + // Legge anno di assitenza e numero massimo di utenti + memcpy(data, &_eprom[60], sizeof(data)); + garble(data); + + if (already) + { + _year_assist = data[0]; + _max_users = data[1]; + const long& giulio = (const long&)data[2]; + const long yyyymmdd = _last_update.julian2date(giulio); + _last_update = yyyymmdd; + } + else + { + _dirty = TRUE; + } + } + else + { + _module.set(255); // Last module on key + _module.set(); // Activate all modules + + _max_users = 1; + _last_update = TDate(TODAY); + _year_assist = _last_update.year(); + } + } + else + _type = _no_dongle; + + return ok; +} + +bool TDongle::eutron_login(bool test_all_keys) +{ + bool ok = FALSE; + if (_eutron_key == NULL) + _eutron_key = new KEY_NET; + memset(_eutron_key, 0, sizeof(KEY_NET)); + _eutron_key->net_command = NET_KEY_OPEN; + + const char* labels[5] = { "AGA.INFORMATICA", "AGA.PRASSI", "AGA.PROCOM", + "AGA.CAMPO", "2699DP" }; + TDongleType types[5] = { _aga_dongle, _prassi_dongle, _procom_dongle, + _user_dongle, _developer_dongle }; + for (int k = test_all_keys ? 0 : 3; k < 5; k++) + { + memset(_eutron_key->label, 0, LABEL_LENGTH); + memcpy(_eutron_key->label, labels[k], strlen(labels[k])); + memset(_eutron_key->password, 0, PASSWORD_LENGTH); + memcpy(_eutron_key->password, ::encode(labels[k]), strlen(labels[k])); + + smartlink(_eutron_key); + ok = _eutron_key->status == ST_OK; + if (ok) + { + _hardware = _dongle_eutron; + _type = types[k]; + break; + } + } + if (ok) + { + _serno = 0; + _max_users = 1; + _last_update = TDate(TODAY); + _year_assist = _last_update.year(); + + if (_type == _user_dongle) + { + _module.reset(); + _module.set(0, TRUE); + if (read_words(0, sizeof(TEutronHeader) / 2, _eprom)) + { + const TEutronHeader* eh = (const TEutronHeader*)_eprom; + TString16 serno; serno.strncpy(eh->_serno, 8); + _serno = unsigned(atol(serno)); + if (already_programmed()) + { + _max_users = eh->_max_users; + _last_update = eh->_last_date; + _year_assist = eh->_year_assist; + + word data[16]; + if (read_words(16, 16, data)) + { + int module = 1; + for (word w = 0; w < 16; w++) + { + for (int b = 0; b < 16; b++) + { + if (test_bit(data[w], b)) + _module.set(module); + module++; + } + } + } + } + else + _dirty = TRUE; + } + } + else + { + _module.set(255); // Last module on key + _module.set(); // Activate all modules + } + } + else + { + delete _eutron_key; + _eutron_key = NULL; + } + return ok; +} + +bool TDongle::network_login(bool test_all_keys) +{ + if (network()) + rpc_UserLogout(); + + TConfig ini(CONFIG_INSTALL, "Server"); + const char* server = ini.get("Dongle"); + const char* guest = "******"; + const TString appname = main_app().firm_change_enabled() ? main_app().name() : "ba0100"; + const char* utente = (!xvt_running() && appname == "ba0100") ? guest : user(); + + const bool ok = rpc_UserLogin(server, utente, guest, appname); + if (ok) + { + _hardware = _dongle_network; + _type = _user_dongle; + _serno = rpc_DongleNumber(); + _max_users = 1; + _last_update = TDate(TODAY); + _year_assist = rpc_DongleYear(); + rpc_DongleModules(_module); + } + return ok; +} + +#endif // _DEMO_ + +bool TDongle::login(bool test_all_keys) +{ + bool ok = TRUE; + +#ifdef _DEMO_ + _hardware = _dongle_hardlock; + _type = _dongle_user; + _serno = 0; + _max_users = 1; + _last_update = TDate(TODAY); + _year_assist = _last_update.year(); + _module.set(255); // Last module on key + _module.set(); // Activate all modules +#else + if (_type != _no_dongle) // Already logged in + logout(); + if (_hardware == _dongle_unknown || _hardware == _dongle_hardlock) + ok = hardlock_login(test_all_keys); + if (_hardware == _dongle_unknown || _hardware == _dongle_eutron) + ok = eutron_login(test_all_keys); + if (_hardware == _dongle_unknown || _hardware == _dongle_network) + ok = network_login(test_all_keys); +#endif + return ok; +} + +bool TDongle::logout() +{ +#ifndef _DEMO_ + if (_type != _no_dongle) + { + switch (_hardware) + { + case _dongle_hardlock: + HL_LOGOUT(); + break; + case _dongle_eutron: + if (_eutron_key) + { + _eutron_key->net_command = NET_KEY_CLOSE; + _eutron_key->command = 0; + smartlink(_eutron_key); + } + break; + case _dongle_network: + rpc_UserLogout(); + break; + default: + break; + } + } +#endif + + _type = _no_dongle; + _serno = 0xFFFF; + + return TRUE; +} + +// Data punta ad un array di 4 words +// Deve essere cosi' per problemi del C, +// non trasformare in array: pena di morte! +bool TDongle::read_words(word reg, word len, word* ud) const +{ + bool ok = FALSE; +#ifndef _DEMO_ + switch (_hardware) + { + case _dongle_hardlock: + { + for (word i = 0; i < len; i++) + HL_READ(reg+i, (int*)&ud[i]); + ok = TRUE; + } + break; + case _dongle_eutron: + if (_eutron_key) + { + _eutron_key->net_command = NET_KEY_ACCESS; + memcpy(&_eutron_key->command, BLOCK_READING_MODE, 2); + word* pointer = (word*)(&_eutron_key->data[0]); + word* number = (word*)(&_eutron_key->data[2]); + *pointer = reg; + *number = len; + smartlink(_eutron_key); + ok = _eutron_key->status == ST_OK; + if (ok) + memcpy(ud, &_eutron_key->data[4], len*2); + else + NFCHECK("EUTRON read error: %d", _eutron_key->status); + } + break; + default: + break; + } +#endif // _DEMO_ + return ok; +} + +// Data punta ad un array di 4 words +// Deve essere cosi' per problemi del C, +// non trasformare in array: pena di morte! +bool TDongle::write_words(word reg, word len, word* data) const +{ + bool ok = FALSE; +#ifndef _DEMO_ + switch(_hardware) + { + case _dongle_hardlock: + { + int err = STATUS_OK; + for (word r = 0; r < len; r++) + { + const word address = reg+r; + err = HL_WRITE(address, data[r]); + if (err != STATUS_OK) + { + NFCHECK("HARDLOCK write error on register %u", address); + break; + } + } + ok = err == STATUS_OK; + } + break; + case _dongle_eutron: + if (_eutron_key) + { + CHECKD(len > 0 && len <= 16, "EUTRON can't write so many words: ", len); + _eutron_key->net_command = NET_KEY_ACCESS; + memcpy(&_eutron_key->command, BLOCK_WRITING_MODE, 2); + word* pointer = (word*)(&_eutron_key->data[0]); + word* number = (word*)(&_eutron_key->data[2]); + *pointer = reg; + *number = len; + memcpy(&_eutron_key->data[4], data, len*2); + smartlink(_eutron_key); + ok = _eutron_key->status == ST_OK; + if (!ok) + NFCHECK("EUTRON write error: %d", _eutron_key->status); + } + default: + break; + } +#endif // _DEMO_ + return ok; +} + +#ifndef _DEMO_ + +bool TDongle::burn_hardlock() +{ + word data[4]; + + const TDate today(TODAY); + const bool already = already_programmed(); + if (already) + { + memcpy(data, &_eprom[60], sizeof(data)); + garble(data); + if (data[0] < 1997 || data[0] > 2997) + return error_box("On Line Assistance error."); + if (data[1] == 0 || data[1] >= 10000) + return error_box("Bad users number."); + const long& val = (const long&)data[2]; + const long yyyymmdd = today.julian2date(val); + const TDate date(yyyymmdd); + if (date > today) + return error_box("Too late sir: key has already expired!"); + } + + data[0] = _year_assist; + data[1] = _max_users; + long& val = (long&)data[2]; + val = today.date2julian(); + garble(data); + write_words(60, 4, data); + _last_update = today; + + // Il primo bit della memoria della chiave corrisponde al modulo uno + // non allo zero (che e' la base ed e' sempre attivo) + word module = 1; + for (int octect = 0; octect < 3; octect++) + { + for(int parola = 0; parola < 3; parola++) + { + word& p = data[parola]; + p = 0; + for (int bit = 0; bit < 16; bit++) + { + if (active(module)) + set_bit(p, bit); + module++; + } + p ^= _serno; + } + data[3] = _serno; + garble(data); + write_words(48 + 4*octect, 4, data); + } + + return TRUE; +} + +bool TDongle::burn_eutron() +{ + TEutronHeader* eh = (TEutronHeader*)_eprom; + memset(eh, 0, sizeof(TEutronHeader)); + + _last_update = TDate(TODAY); + sprintf(eh->_serno, "%lu", _serno); + eh->_year_assist = _year_assist; + eh->_max_users = _max_users; + eh->_last_date = atol(_last_update.string(ANSI)); + eh->_scad_date = 0; + + unsigned long cs = 0; + for (byte* ptr = (byte*)_eprom; ptr < (byte*)&eh->_checksum; ptr++) + cs += *ptr | ~(*ptr << 8); + eh->_checksum = cs; + + bool ok = write_words(0, sizeof(TEutronHeader)/2, _eprom); + if (ok) + { + word data[16]; memset(data, 0, sizeof(data)); + for (int module = 1; module < 256; module++) + { + if (active(module)) + { + word& w = data[(module-1) / 16]; + set_bit(w, (module-1) % 16, TRUE); + } + } + ok = write_words(16, 16, data); + } + + return ok; +} +#endif // _DEMO_ + +bool TDongle::burn() +{ + bool ok = local() && _type == _user_dongle; + +#ifndef _DEMO_ + if (ok) + { + switch(_hardware) + { + case _dongle_hardlock: ok = burn_hardlock(); break; + case _dongle_eutron : ok = burn_eutron(); break; + default : break; + } + } +#endif + if (ok) + _dirty = FALSE; + + return ok; +} diff --git a/include/dongle.h b/include/dongle.h new file mode 100755 index 000000000..966e9c2b3 --- /dev/null +++ b/include/dongle.h @@ -0,0 +1,79 @@ +#ifndef __DONGLE_H +#define __DONGLE_H + +#ifndef __DATE_H +#include +#endif + +#ifndef __STRINGS_H +#include +#endif + +enum TDongleHardware { _dongle_unknown, _dongle_hardlock, _dongle_eutron, _dongle_network }; +enum TDongleType { _no_dongle, _user_dongle, _developer_dongle, _aga_dongle, _prassi_dongle, _procom_dongle }; + +class TDongle : public TObject +{ + TDongleHardware _hardware; + TDongleType _type; + + word _serno, _max_users, _year_assist; + word _eprom[64]; + TDate _last_update; + TBit_array _module; + bool _dirty; + +protected: + bool already_programmed() const; + + bool hardlock_login(bool test_all_dongles); + bool eutron_login(bool test_all_dongles); + bool network_login(bool test_all_dongles); + + bool burn_hardlock(); + bool burn_eutron(); + +public: // TObject + virtual bool ok() const + { return _hardware != _dongle_unknown && + _type != _no_dongle && + _serno != 0xFFFF; } + +public: + bool login(bool test_all_dongles = FALSE); + bool logout(); + + word number() const { return _serno; } + word max_users() const { return _max_users; } + word year_assist() const { return _year_assist; } + + void garble(word* data) const; + + // Solo per un po' di tempo, poi diverranno protected (servono a ba1500 old style) + bool read_words(word reg, word len, word *data) const; + bool write_words(word reg, word len, word *data) const; + + TDongleType type() const { return _type; } + + bool active(word module) const { return _module[module]; } + void activate(word module, bool on = TRUE) { _module.set(module, on); _dirty = TRUE; } + void deactivate(word module) { activate(module, FALSE); } + void set_max_users(word u) { _max_users = u; _dirty = TRUE; } + void set_year_assist(word y) { _year_assist = y; _dirty = TRUE; } + const TDate& last_update() const { return _last_update; } + + bool dirty() const { return _dirty; } + bool burn(); + + TDongleHardware hardware() const { return _hardware; } + bool local() const { return _hardware == _dongle_hardlock || _hardware == _dongle_eutron; } + bool network() const { return _hardware == _dongle_network; } + + TDongle(); + virtual ~TDongle(); +}; + +TDongle& dongle(); +bool destroy_dongle(); + +#endif diff --git a/include/execp.cpp b/include/execp.cpp index bb35745a2..d66416616 100755 --- a/include/execp.cpp +++ b/include/execp.cpp @@ -13,9 +13,8 @@ #include #endif -#include - #include +#include #include #include #include @@ -151,7 +150,8 @@ word TExternal_app::run( { TWait_cursor hourglass; #if XVT_OS == XVT_OS_WIN - HL_LOGOUT(); + if (dongle().local()) + dongle().logout(); _exitcode = WinExec((const char*)path, show ? SW_SHOWNORMAL : SW_HIDE); if (_exitcode >= 32) @@ -347,7 +347,8 @@ word TExternal_app::run( // non ci saranno piu' posti liberi nell'HL_server: il programma comunque non // puo' interrompersi a meta'; ecco perche il valore di ritorno di HL_LOGIN viene // ignorato. - HL_LOGIN(ModAd, DONT_CARE, REFKEY, VERKEY); + if (dongle().local()) + dongle().login(); #endif return _exitcode; }