// dllmain.cpp : Defines the entry point for the DLL application. #include "pch.h" #include "iobox_api.h" #include #include #include #include #include // Handle registry with refcount — prevents use-after-free when // ReleaseANSIOHandle is called while an operation is still running. static std::unordered_map& IOHandleRegistry() { static std::unordered_map s; return s; } static std::mutex& IOHandleRegistryMutex() { static std::mutex m; return m; } static std::condition_variable& IOHandleRegistryCV() { static std::condition_variable cv; return cv; } static void RegisterIOHandle(ANSCENTER::iobox_api* h) { std::lock_guard lk(IOHandleRegistryMutex()); IOHandleRegistry()[h] = 1; } static ANSCENTER::iobox_api* AcquireIOHandle(ANSCENTER::iobox_api* h) { std::lock_guard lk(IOHandleRegistryMutex()); auto it = IOHandleRegistry().find(h); if (it == IOHandleRegistry().end()) return nullptr; it->second++; return h; } static bool ReleaseIOHandleRef(ANSCENTER::iobox_api* h) { std::lock_guard lk(IOHandleRegistryMutex()); auto it = IOHandleRegistry().find(h); if (it == IOHandleRegistry().end()) return false; it->second--; if (it->second <= 0) { IOHandleRegistry().erase(it); IOHandleRegistryCV().notify_all(); return true; } return false; } static bool UnregisterIOHandle(ANSCENTER::iobox_api* h) { std::unique_lock lk(IOHandleRegistryMutex()); auto it = IOHandleRegistry().find(h); if (it == IOHandleRegistry().end()) return false; it->second--; bool ok = IOHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() { auto it2 = IOHandleRegistry().find(h); return it2 == IOHandleRegistry().end() || it2->second <= 0; }); if (!ok) { OutputDebugStringA("WARNING: UnregisterIOHandle timed out waiting for in-flight operations\n"); } IOHandleRegistry().erase(h); return true; } // RAII guard — ensures ReleaseIOHandleRef is always called class IOHandleGuard { ANSCENTER::iobox_api* engine; public: explicit IOHandleGuard(ANSCENTER::iobox_api* e) : engine(e) {} ~IOHandleGuard() { if (engine) ReleaseIOHandleRef(engine); } ANSCENTER::iobox_api* get() const { return engine; } explicit operator bool() const { return engine != nullptr; } IOHandleGuard(const IOHandleGuard&) = delete; IOHandleGuard& operator=(const IOHandleGuard&) = delete; }; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) noexcept { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // Helper: safely copy a std::string into a LabVIEW LStrHandle. // Returns 1 on success, 0 on failure (empty string or allocation error). static int CopyToLStrHandle(LStrHandle handle, const std::string& str) noexcept { if (str.empty() || handle == nullptr) return 0; const auto size = static_cast(str.length()); MgErr error = DSSetHandleSize(handle, sizeof(int32) + size * sizeof(uChar)); if (error != noErr) return 0; (*handle)->cnt = size; memcpy((*handle)->str, str.c_str(), static_cast(size)); return 1; } // Helper: join a vector of strings with semicolon separator. static std::string JoinStrings(const std::vector& items) { std::string result; for (size_t i = 0; i < items.size(); ++i) { if (i > 0) result += ";"; result += items[i]; } return result; } extern "C" ANSIO_API int CreateANSIOHandle(ANSCENTER::iobox_api** Handle, const char* multicastIPAddress, int multicastPort) { if (Handle == nullptr || multicastIPAddress == nullptr) return 0; try { // Release existing handle if called twice (prevents leak from LabVIEW) if (*Handle) { if (UnregisterIOHandle(*Handle)) { delete *Handle; } *Handle = nullptr; } // std::unique_ptr ensures automatic cleanup on any failure path auto ptr = std::make_unique(multicastIPAddress, multicastPort); // Transfer ownership to caller on success *Handle = ptr.release(); RegisterIOHandle(*Handle); return 1; } catch (const std::exception&) { if (Handle) *Handle = nullptr; return 0; } catch (...) { if (Handle) *Handle = nullptr; return 0; } } extern "C" ANSIO_API int ConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0; try { return CopyToLStrHandle(deviceStr, guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, LStrHandle deviceStr) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0; try { std::vector st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord); if (st.empty()) return 0; return CopyToLStrHandle(deviceStr, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int DisconnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { return guard.get()->disconnectToIoboxWithResetOutputs(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } static int ReleaseANSIOHandle_Impl(ANSCENTER::iobox_api** Handle) { try { if (!Handle || !*Handle) return 1; if (!UnregisterIOHandle(*Handle)) { *Handle = nullptr; return 1; } delete *Handle; *Handle = nullptr; return 1; } catch (...) { if (Handle) *Handle = nullptr; return 0; } } extern "C" ANSIO_API int ReleaseANSIOHandle(ANSCENTER::iobox_api** Handle) { __try { return ReleaseANSIOHandle_Impl(Handle); } __except (EXCEPTION_EXECUTE_HANDLER) { if (Handle) *Handle = nullptr; return 0; } } extern "C" ANSIO_API int SetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0; try { return guard.get()->setValue(ioBoxIP, channelName, value) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { std::string st = "fail"; bool success = guard.get()->getValue(ioBoxIP, channelName, st); if (!success || st.empty() || st == "fail") return 0; return CopyToLStrHandle(lStrValue, st); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* userName, const char* passWord) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0; try { return guard.get()->setAuthenticationIobox(ioBoxIP, userName, passWord) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesMulticast(timeout); if (st.empty()) return 0; return CopyToLStrHandle(ipAddresses, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOUnicastHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesManually(timeout); if (st.empty()) return 0; return CopyToLStrHandle(ipAddresses, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle deviceInfos) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->advancedScan(timeout); if (st.empty()) return 0; return CopyToLStrHandle(deviceInfos, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedStaticScanANSIOHandle(int timeout, LStrHandle deviceInfos) { try { ANSCENTER::iobox_api iobox_api("239.255.255.250", 12345); std::vector st = iobox_api.advancedScan(timeout); if (st.empty()) return 0; return CopyToLStrHandle(deviceInfos, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesMulticast(timeout); if (st.empty()) return 0; ipAddresses = JoinStrings(st); return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOUnicastHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesManually(timeout); if (st.empty()) return 0; ipAddresses = JoinStrings(st); return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& deviceInfos) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->advancedScan(timeout); if (st.empty()) return 0; deviceInfos = JoinStrings(st); return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedStaticScanANSIOHandle_CPP(int timeout, std::string& deviceInfos) { try { ANSCENTER::iobox_api iobox_api("239.255.255.250", 12345); std::vector st = iobox_api.advancedScan(timeout); if (st.empty()) return 0; deviceInfos = JoinStrings(st); if (deviceInfos.empty()) return 0; return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetChannelNamesANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, LStrHandle channelNames) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->getDeviceChannelNames(ioBoxIP); if (st.empty()) return 0; return CopyToLStrHandle(channelNames, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetValueANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, std::string& lStrValue) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { std::string st = "fail"; bool success = guard.get()->getValue(ioBoxIP, channelName, st); if (!success || st.empty() || st == "fail") return 0; lStrValue = st; return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetChannelNamesANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, std::string& channelNames) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector st = guard.get()->getDeviceChannelNames(ioBoxIP); if (st.empty()) return 0; channelNames = JoinStrings(st); return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ResetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || token == nullptr) return 0; try { return guard.get()->resetAuthenticationIobox(ioBoxIP, token) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ResetANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || token == nullptr) return 0; try { return guard.get()->resetIobox(ioBoxIP, token) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GenerateANSIOTokenHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle tokenStr) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { return CopyToLStrHandle(tokenStr, guard.get()->generateToken(ioBoxIP)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GenerateANSIOTokenHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, std::string& tokenStr) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::string st = guard.get()->generateToken(ioBoxIP); if (st.empty()) return 0; tokenStr = st; return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, std::string& deviceStr) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0; try { std::string st = guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord); if (st.empty()) return 0; deviceStr = st; return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, std::string& deviceStr) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0; try { std::vector st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord); if (st.empty()) return 0; deviceStr = JoinStrings(st); return 1; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int CheckANSIOStatusHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { return guard.get()->checkTcpConnectStatus(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int OpenANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int baudrate, int DataBits, int stopBits, int parityBits) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { return guard.get()->openRs232Port(ioBoxIP, baudrate, DataBits, stopBits, parityBits) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int CloseANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { return guard.get()->closeRs232Port(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int WriteANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* data, int timeout_ms) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || data == nullptr) return 0; try { return guard.get()->writeRs232Port(ioBoxIP, data, timeout_ms) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ReadANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* terminatorString, int lenExpect, int timeout_ms, LStrHandle receivedData) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { const char* safeTerminator = (terminatorString != nullptr) ? terminatorString : ""; return CopyToLStrHandle(receivedData, guard.get()->readRs232Port(ioBoxIP, safeTerminator, lenExpect, timeout_ms)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } // OTA extern "C" ANSIO_API int OTAANSIOFirmwareDevice(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* filename, const char* type) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || filename == nullptr || type == nullptr) return 0; try { return guard.get()->otaFirmwareDevice(ioBoxIP, filename, type) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } // Synchronous version (existing behavior) extern "C" ANSIO_API int ToggleIoboxHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) { try { // Input validation if (Handle == nullptr || *Handle == nullptr) { return -1; // Invalid handle } IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return -1; if (ioBoxIP == nullptr || channelName == nullptr) { return -2; // Invalid parameters } if (timeOut < 0) { return -3; // Invalid timeout } // Convert C parameters to C++ types std::string remote(ioBoxIP); std::string channel(channelName); bool revert = (revertFlag != 0); bool reset = (resetFlag != 0); // Call synchronous version (asyncMode = false) bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, false); return result ? 1 : 0; } catch (const std::exception&) { return -4; // Exception occurred } catch (...) { return -5; // Unknown exception } } // Asynchronous version (new function) extern "C" ANSIO_API int ToggleIoboxHandleAsync(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) { try { // Input validation if (Handle == nullptr || *Handle == nullptr) { return -1; // Invalid handle } IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return -1; if (ioBoxIP == nullptr || channelName == nullptr) { return -2; // Invalid parameters } if (timeOut < 0) { return -3; // Invalid timeout } // Convert C parameters to C++ types std::string remote(ioBoxIP); std::string channel(channelName); bool revert = (revertFlag != 0); bool reset = (resetFlag != 0); // Call asynchronous version (asyncMode = true) bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, true); return result ? 1 : 0; // Returns immediately } catch (const std::exception&) { return -4; // Exception occurred } catch (...) { return -5; // Unknown exception } } extern "C" ANSIO_API int GetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle staticIpConfigInfo) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; try { std::vector configs = guard.get()->getStaticIpConfig(ioBoxIP); if (configs.empty()) return 0; return CopyToLStrHandle(staticIpConfigInfo, JoinStrings(configs)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int enable, const char* ip, const char* gw, const char* nm) { if (Handle == nullptr || *Handle == nullptr || ioBoxIP == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ip == nullptr || gw == nullptr || nm == nullptr) return 0; try { return guard.get()->setStaticIpConfig(ioBoxIP, enable != 0, ip, gw, nm) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle dataValue) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { return CopyToLStrHandle(dataValue, guard.get()->getValueDataStringIoboxFromChannelName(ioBoxIP, channelName)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ToggleDigitalOutputANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int milliseconds, int invertFlag, int resetFlag) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { return guard.get()->toggleDigitalOutput(ioBoxIP, channelName, std::to_string(milliseconds), invertFlag != 0, resetFlag != 0) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetAIBValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value) { if (Handle == nullptr || *Handle == nullptr) return 0; IOHandleGuard guard(AcquireIOHandle(*Handle)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0; try { return guard.get()->setAIBValueDataStringIoboxFromChannelName(ioBoxIP, channelName, value) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } // ============================================================================ // V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug // ============================================================================ extern "C" ANSIO_API int ConnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0; try { return CopyToLStrHandle(deviceStr, guard.get()->connectToIobox(ioBoxIP, ioBoxPort, userName, passWord)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedConnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, LStrHandle deviceStr) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || ioBoxSN == nullptr || userName == nullptr || passWord == nullptr) return 0; try { std::vector st = guard.get()->advancedConnectToIobox(ioBoxIP, ioBoxPort, ioBoxSN, userName, passWord); if (st.empty()) return 0; return CopyToLStrHandle(deviceStr, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int DisconnectANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { return guard.get()->disconnectToIoboxWithResetOutputs(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int CheckANSIOStatusHandle_V2(uint64_t handleVal, const char* ioBoxIP) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { return guard.get()->checkTcpConnectStatus(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetValueANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, const char* value) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0; try { return guard.get()->setValue(ioBoxIP, channelName, value) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetValueANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { std::string st = "fail"; bool success = guard.get()->getValue(ioBoxIP, channelName, st); if (!success || st.empty() || st == "fail") return 0; return CopyToLStrHandle(lStrValue, st); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetValueDataStringIoboxFromChannelNameANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, LStrHandle dataValue) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { return CopyToLStrHandle(dataValue, guard.get()->getValueDataStringIoboxFromChannelName(ioBoxIP, channelName)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetAIBValueDataStringIoboxFromChannelNameANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, const char* value) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr || value == nullptr) return 0; try { return guard.get()->setAIBValueDataStringIoboxFromChannelName(ioBoxIP, channelName, value) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetAuthenticationANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* userName, const char* passWord) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || userName == nullptr || passWord == nullptr) return 0; try { return guard.get()->setAuthenticationIobox(ioBoxIP, userName, passWord) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ResetAuthenticationANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* token) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || token == nullptr) return 0; try { return guard.get()->resetAuthenticationIobox(ioBoxIP, token) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GenerateANSIOTokenHandle_V2(uint64_t handleVal, const char* ioBoxIP, LStrHandle tokenStr) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { return CopyToLStrHandle(tokenStr, guard.get()->generateToken(ioBoxIP)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOHandle_V2(uint64_t handleVal, int timeout, LStrHandle ipAddresses) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesMulticast(timeout); if (st.empty()) return 0; return CopyToLStrHandle(ipAddresses, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ScanANSIOUnicastHandle_V2(uint64_t handleVal, int timeout, LStrHandle ipAddresses) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; try { std::vector st = guard.get()->scanNetworkDevicesManually(timeout); if (st.empty()) return 0; return CopyToLStrHandle(ipAddresses, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int AdvancedScanANSIOHandle_V2(uint64_t handleVal, int timeout, LStrHandle deviceInfos) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; try { std::vector st = guard.get()->advancedScan(timeout); if (st.empty()) return 0; return CopyToLStrHandle(deviceInfos, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetChannelNamesANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int timeout, LStrHandle channelNames) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { std::vector st = guard.get()->getDeviceChannelNames(ioBoxIP); if (st.empty()) return 0; return CopyToLStrHandle(channelNames, JoinStrings(st)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ResetANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* token) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || token == nullptr) return 0; try { return guard.get()->resetIobox(ioBoxIP, token) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ToggleIoboxHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return -1; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return -1; if (ioBoxIP == nullptr || channelName == nullptr) return -2; if (timeOut < 0) return -3; try { std::string remote(ioBoxIP); std::string channel(channelName); bool revert = (revertFlag != 0); bool reset = (resetFlag != 0); bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, false); return result ? 1 : 0; } catch (const std::exception&) { return -4; } catch (...) { return -5; } } extern "C" ANSIO_API int ToggleIoboxHandleAsync_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return -1; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return -1; if (ioBoxIP == nullptr || channelName == nullptr) return -2; if (timeOut < 0) return -3; try { std::string remote(ioBoxIP); std::string channel(channelName); bool revert = (revertFlag != 0); bool reset = (resetFlag != 0); bool result = guard.get()->toggleIobox(remote, channel, timeOut, revert, reset, true); return result ? 1 : 0; } catch (const std::exception&) { return -4; } catch (...) { return -5; } } extern "C" ANSIO_API int ToggleDigitalOutputANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, const char* channelName, int milliseconds, int invertFlag, int resetFlag) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || channelName == nullptr) return 0; try { return guard.get()->toggleDigitalOutput(ioBoxIP, channelName, std::to_string(milliseconds), invertFlag != 0, resetFlag != 0) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int OpenANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, int baudrate, int DataBits, int stopBits, int parityBits) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { return guard.get()->openRs232Port(ioBoxIP, baudrate, DataBits, stopBits, parityBits) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int CloseANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { return guard.get()->closeRs232Port(ioBoxIP) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int WriteANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, const char* data, int timeout_ms) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || data == nullptr) return 0; try { return guard.get()->writeRs232Port(ioBoxIP, data, timeout_ms) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int ReadANSAIRS232Port_V2(uint64_t handleVal, const char* ioBoxIP, const char* terminatorString, int lenExpect, int timeout_ms, LStrHandle receivedData) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { const char* safeTerminator = (terminatorString != nullptr) ? terminatorString : ""; return CopyToLStrHandle(receivedData, guard.get()->readRs232Port(ioBoxIP, safeTerminator, lenExpect, timeout_ms)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int GetStaticIpConfigANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, LStrHandle staticIpConfigInfo) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr) return 0; try { std::vector configs = guard.get()->getStaticIpConfig(ioBoxIP); if (configs.empty()) return 0; return CopyToLStrHandle(staticIpConfigInfo, JoinStrings(configs)); } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int SetStaticIpConfigANSIOHandle_V2(uint64_t handleVal, const char* ioBoxIP, int enable, const char* ip, const char* gw, const char* nm) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || ip == nullptr || gw == nullptr || nm == nullptr) return 0; try { return guard.get()->setStaticIpConfig(ioBoxIP, enable != 0, ip, gw, nm) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } extern "C" ANSIO_API int OTAANSIOFirmwareDevice_V2(uint64_t handleVal, const char* ioBoxIP, const char* filename, const char* type) { auto* _v2h = reinterpret_cast(handleVal); if (!_v2h) return 0; IOHandleGuard guard(AcquireIOHandle(_v2h)); if (!guard) return 0; if (ioBoxIP == nullptr || filename == nullptr || type == nullptr) return 0; try { return guard.get()->otaFirmwareDevice(ioBoxIP, filename, type) ? 1 : 0; } catch (const std::exception&) { return 0; } catch (...) { return 0; } } // End of ANSIO/dllmain.cpp