首页/文档/SDK 接入

智链系统 SDK 接入

从后台拿到 product_token,到跑通第一个卡密登录。Windows DLL 与 Linux .so 使用同一套接口;另附 21 种语言的协议源码示例。

SDK v1.0.064 个导出函数Windows / Linux约 15 分钟

01这是什么

智链系统 SDK 是智链网络验证的客户端 SDK:Windows 下是 DLL,Linux 下是 .so,两个平台的函数名、参数、返回值完全一致。你的程序只要调用它,就能完成卡密登录、账号登录、到期检测、点数扣减、远程变量与云函数等流程。

  • 登录验证:卡密登录、账号密码登录、设备试用登录
  • 状态维护:心跳保活、到期时间、账号状态
  • 账号体系:注册、充值、改密、找回密码、转绑
  • 数据交互:公告、远程变量、远程函数、账号云数据、点数
  • 加壳配套:WinLicense 授权、VMP 授权码
你不需要自己处理:请求加密、响应验签、时间戳防重放、机器码采集、心跳周期、挑战码——SDK 内部已经自动完成。你只需要关心「登录是否成功、业务数据是什么」。

02两种接入方式

方式适合入口难度
原生 SDK桌面程序:C/C++、C#、Python、易语言、Delphi、VB6ZhilianSDK_x64.dll / libZhilianSDK.so,三行调用最低
协议源码Web、服务端、脚本、跨平台程序POST /api/open,21 种语言示例中等

两种方式共用同一个应用、同一套卡密与授权数据,可以混用:桌面端用原生 SDK,服务端用协议源码,登录 token 与用户体系是同一套。

怎么选:能给 exe / dll 加壳、只是要做登录验证,选原生 SDK;程序本身是 Web 服务、Go / Java / Node 后端,或需要自定义业务逻辑,选协议源码。协议源码的完整清单见 多语言源码清单。

03目录与下载

智链系统 SDK 完整包

Windows x64 / x86 DLL、Linux .so、导入库、头文件、21 种语言示例与原始接入文档。
压缩包约 22 MB。

文件 / 目录用途
Zhi_Liani_SDK/Win_SDK/ZhilianSDK_x64.dll64 位程序主文件,放 exe 同目录
Zhi_Liani_SDK/Win_SDK/ZhilianSDK_x86.dll32 位程序(易语言、VB6、Delphi 32 位)
Zhi_Liani_SDK/Win_SDK/*.libC/C++ 导入库,仅静态链接时需要
Zhi_Liani_SDK/Win_SDK/ZhilianSDK.hC/C++ 头文件,函数原型与错误码
Zhi_Liani_SDK/Linux_SDK/libZhilianSDK.soLinux x86_64 全部内容,单文件
python/ go/ java/ C#/ C/ C++/ …21 种语言的协议源码示例
Zhi_Liani_SDK/ZhilianSDK_接入文档.htmlSDK 原始接入文档(本页的精简来源)
位数必须匹配:64 位程序加载 x64 DLL,32 位程序加载 x86 DLL;Linux 目前只提供 x86_64。搞反会报「无法加载 DLL」或 0xC0000135。

045 分钟接入

1

拿到对接参数

登录验证后台 → 进入应用 → 点「一键生成对接参数」→ 复制整串加密文本(product_token)。这串内容已经包含服务器地址、应用 UUID、加密密钥、验签公钥与算法,不需要再手填。

2

把库放到程序目录

Windows:把 ZhilianSDK_x64.dll 或 ZhilianSDK_x86.dll 放到 exe 旁边。
Linux:把 libZhilianSDK.so 放程序同目录,编译时加 -Wl,-rpath,'$ORIGIN'。

3

三步调用

ZL_Create → ZL_SetConfig(对接串) → ZL_CardLogin(卡密)。登录成功后开启自动心跳,再用 ZL_GetResult 取业务数据。

#include "ZhilianSDK.h"
#include <stdio.h>

int main(void) {
    ZL_HANDLE h = ZL_Create();
    if (!h) return 1;

    /* ① 粘贴后台「一键生成对接参数」里的整串 */
    if (ZL_SetConfig(h, "这里粘贴 product_token") != 0) {
        char err[512];
        ZL_GetLastErrorMessage(h, err, sizeof(err));
        printf("配置失败: %s\n", err);
        ZL_Destroy(h);
        return 1;
    }

    /* ② 卡密登录 */
    if (ZL_CardLogin(h, "你的卡密") != 0) {
        char err[512];
        ZL_GetLastErrorMessage(h, err, sizeof(err));
        printf("登录失败: %s\n", err);
        ZL_Destroy(h);
        return 1;
    }

    /* ③ 开自动心跳(默认关闭,建议打开) */
    ZL_SetAutoHeartbeat(h, 1, 0);

    /* ④ 取业务数据 */
    char buf[65536];
    ZL_GetExpire(h);
    ZL_GetResult(h, buf, sizeof(buf));
    printf("到期信息: %s\n", buf);

    ZL_Logout(h);
    ZL_Destroy(h);
    return 0;
}
就这么点代码。加密、签名、机器码、挑战码都在 ZL_SetConfig 与 ZL_CardLogin 内部自动完成。

05配置参数

方式一:整串配置(推荐)

直接把后台生成的 product_token 交给 ZL_SetConfig:

ZL_SetConfig(h, "后台复制的那一整串");

返回 0 表示成功;返回 -2 表示这串内容不合法(抄漏、被改过、或不是对接串)。对接串是加密的,改了字符就解不开,SDK 会直接拒绝。

方式二:逐项设置(一般不用)

函数说明必填
ZL_SetServer服务器地址,如 https://your-server.com,不要带 /api/open是
ZL_SetAppUUID后台应用 UUID是
ZL_SetSecretEd25519 验签公钥(方案 1)或对称 Secret(方案 0)是
ZL_SetKeysAES 与 ChaCha20 密钥(64 位 hex)按算法
ZL_SetCryptoalgorithm:0 明文 / 1 AES / 2 ChaCha20;sign_scheme:0 对称 / 1 Ed25519是
ZL_SetClientVersion你的程序版本号,如 1.0.0建议
ZL_SetProgramName程序名,用于后台显示选填
配置不完整时调用任何接口都会返回 -3,错误信息里会直接写「缺少:xxx」,照着补即可。

其它可调项

函数作用默认
ZL_SetAutoHeartbeat开启内置自动心跳线程,interval=0 跟随服务端周期关闭
ZL_SetMachineRule机器码采集方案,见下文「机器码」规则 2
ZL_SetMachineId手动指定机器码,覆盖自动生成自动
ZL_SetDeviceName设备名,默认「系统名-计算机名」自动
ZL_SetChallengeMode挑战码:-1 自动 / 0 关闭 / 1 强制-1

06调用流程

ZL_Create()                 创建实例,拿到句柄
      │
ZL_SetConfig(对接串)         配置(一次性)
      │
ZL_SetAutoHeartbeat(1, 0)   开自动心跳(建议)
      │
ZL_CardLogin(卡密)           登录 → 成功返回 0
      │  └─ 失败:ZL_GetLastErrorMessage 取原因
      │
   ┌──┴──────────────────────┐
   │  业务调用                │
   │  ZL_GetExpire            │
   │  ZL_GetNotice            │
   │  ZL_GetVariable          │
   │  ZL_PointsDeduct         │
   │  ...                     │
   └──┬──────────────────────┘
      │
ZL_Logout()                 退出登录
      │
ZL_Destroy()                销毁实例(自动停心跳、释放资源)
ZL_Destroy 必须调用。否则心跳线程和句柄资源不会释放,程序退出前记得销毁。

结果怎么取

所有业务接口只返回一个 int(成功 0 / 失败非 0),真正的数据用 ZL_GetResult 取:

char buf[65536];
int r = ZL_GetExpire(h);
if (r == 0) {
    ZL_GetResult(h, buf, sizeof(buf));
    // buf 里是 JSON,例如:
    // {"code":0,"data":{"expired_at":"2026-12-31T23:59:59+08:00",...}}
    printf("%s\n", buf);
} else {
    char err[512];
    ZL_GetLastErrorMessage(h, err, sizeof(err));
    printf("失败(%d): %s\n", r, err);
}
缓冲区建议不低于 64 KB:公告、账号数据可能较长。缓冲区不够时 ZL_GetResult 返回 -9,内容会被截断,不会崩溃。

07C / C++

C/C++ 直接包含 ZhilianSDK.h,链接 ZhilianSDK_x64.lib 或 ZhilianSDK_x86.lib,运行时把对应 DLL 放 exe 同目录。

#pragma comment(lib, "ZhilianSDK_x64.lib")

ZL_HANDLE h = ZL_Create();
ZL_SetConfig(h, token);
if (ZL_CardLogin(h, card) == 0) {
    ZL_SetAutoHeartbeat(h, 1, 0);
    // 登录成功,继续业务
}
ZL_Destroy(h);

完整可运行示例见压缩包 C/main.c 与 C++/main.cpp;C/C++ 协议示例还带 deps/(libcurl + LibreSSL + cJSON / json.hpp),运行 build.sh 即可编译。

08C#

用 DllImport 声明,调用约定统一 StdCall,字符串用 CharSet.Ansi(UTF-8 传入)。

using System;
using System.Runtime.InteropServices;
using System.Text;

class ZL {
    const string D = "ZhilianSDK_x64.dll";

    [DllImport(D, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr ZL_Create();

    [DllImport(D, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    public static extern int ZL_SetConfig(IntPtr h, string json);

    [DllImport(D, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    public static extern int ZL_CardLogin(IntPtr h, string card);

    [DllImport(D, CallingConvention = CallingConvention.StdCall)]
    public static extern int ZL_SetAutoHeartbeat(IntPtr h, int enable, int interval);

    [DllImport(D, CallingConvention = CallingConvention.StdCall)]
    public static extern int ZL_GetExpire(IntPtr h);

    [DllImport(D, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    public static extern int ZL_GetResult(IntPtr h, StringBuilder buf, uint size);

    [DllImport(D, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
    public static extern int ZL_GetLastErrorMessage(IntPtr h, StringBuilder buf, uint size);

    [DllImport(D, CallingConvention = CallingConvention.StdCall)]
    public static extern void ZL_Destroy(IntPtr h);
}

// 调用
IntPtr h = ZL.ZL_Create();
if (ZL.ZL_SetConfig(h, token) != 0) { /* 失败 */ }
if (ZL.ZL_CardLogin(h, "卡密") == 0) {
    ZL.ZL_SetAutoHeartbeat(h, 1, 0);

    var buf = new StringBuilder(65536);
    ZL.ZL_GetExpire(h);
    ZL.ZL_GetResult(h, buf, 65536);
    Console.WriteLine(buf.ToString());
}
ZL.ZL_Destroy(h);
C# 的协议版完整示例在 C#/ZhiLianClient.cs,原生 DLL 版按上面的声明补全即可。

09Python

用 ctypes 加载 DLL。务必先设 restype = c_void_p,否则 64 位下句柄会被截断。

import ctypes, os

os.add_dll_directory(os.path.dirname(os.path.abspath(__file__)))
dll = ctypes.WinDLL("ZhilianSDK_x64.dll")

H, S, U = ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32
dll.ZL_Create.restype = H
dll.ZL_SetConfig.argtypes = [H, S]
dll.ZL_CardLogin.argtypes = [H, S]
dll.ZL_GetExpire.argtypes = [H]
dll.ZL_GetResult.argtypes = [H, S, U]
dll.ZL_SetAutoHeartbeat.argtypes = [H, ctypes.c_int, ctypes.c_int]
dll.ZL_GetLastErrorMessage.argtypes = [H, S, U]
dll.ZL_Logout.argtypes = [H]
dll.ZL_Destroy.argtypes = [H]

token = open("product_token.txt", encoding="utf-8").read().strip().encode()
h = dll.ZL_Create()
assert dll.ZL_SetConfig(h, token) == 0
assert dll.ZL_CardLogin(h, b"你的卡密") == 0

dll.ZL_SetAutoHeartbeat(h, 1, 0)
buf = ctypes.create_string_buffer(65536)
dll.ZL_GetExpire(h)
dll.ZL_GetResult(h, buf, 65536)
print(buf.value.decode("utf-8", "replace"))

dll.ZL_Logout(h)
dll.ZL_Destroy(h)
Python 里字符串参数是 bytes(.encode()),返回值用 .decode("utf-8");每个函数都要设 restype / argtypes。

10易语言

易语言编译出来是 32 位程序,请使用 ZhilianSDK_x86.dll。菜单「插入 → DLL 命令」,按下面填写:

项目填写内容
DLL 命令名ZL_Create
返回值类型整数型
库文件名ZhilianSDK_x86.dll
在库中对应命令名ZL_Create
调用方式stdcall(必须)

按同样方式依次添加 ZL_SetConfig(句柄、配置串)、ZL_CardLogin(句柄、卡密)、ZL_GetResult(句柄、缓冲区传址、长度)、ZL_GetLastErrorMessage、ZL_SetAutoHeartbeat、ZL_Destroy。

.局部变量 句柄, 整数型
.局部变量 结果, 文本型

句柄 = ZL_Create ()
.如果真 (ZL_SetConfig (句柄, 配置串) ≠ 0)
    信息框 (“配置失败”, 0, , )
    返回 ()
.如果真结束

.如果真 (ZL_CardLogin (句柄, 卡密) ≠ 0)
    结果 = 取空白文本 (512)
    ZL_GetLastErrorMessage (句柄, 结果, 512)
    信息框 (结果, 0, , )
    ZL_Destroy (句柄)
    返回 ()
.如果真结束

ZL_SetAutoHeartbeat (句柄, 1, 0)
' ... 业务代码 ...
ZL_Destroy (句柄)
中文乱码:接口返回 UTF-8。易语言用 ZL_Utf8ToAnsi(utf8, 缓冲, 长度) 转成 GBK 再显示。

11Delphi / VB6

调用约定统一 stdcall,字符串统一 UTF-8 的 char*。

// Delphi
function ZL_Create: Pointer; stdcall; external 'ZhilianSDK_x86.dll';
function ZL_SetConfig(h: Pointer; cfg: PAnsiChar): Integer; stdcall; external 'ZhilianSDK_x86.dll';
function ZL_CardLogin(h: Pointer; card: PAnsiChar): Integer; stdcall; external 'ZhilianSDK_x86.dll';
// VB6
Private Declare Function ZL_Create Lib "ZhilianSDK_x86.dll" () As Long
Private Declare Function ZL_SetConfig Lib "ZhilianSDK_x86.dll" (ByVal h As Long, ByVal cfg As String) As Long
Private Declare Function ZL_CardLogin Lib "ZhilianSDK_x86.dll" (ByVal h As Long, ByVal card As String) As Long

压缩包里的 delphi/ZhiLianDemo.dpr、lazarus/ZhiLianDemo.lpr 是完整工程,可直接用 IDE 编译。

12Linux .so

Linux 版与 Windows 版由同一份源码编译,64 个函数名、参数、返回值完全一致。运行时只需要一个 libZhilianSDK.so(x86_64,约 895 KB,glibc ≥ 2.17)。

# C
gcc main.c -I. -L. -lZhilianSDK -Wl,-rpath,'$ORIGIN' -o myapp

# C++
g++ main.cpp -I. -L. -lZhilianSDK -Wl,-rpath,'$ORIGIN' -o myapp

-Wl,-rpath,'$ORIGIN' 让程序优先在自身目录找 .so;也可以把 .so 装到 /usr/local/lib 后执行 ldconfig,或临时设 LD_LIBRARY_PATH。

import ctypes

lib = ctypes.CDLL("./libZhilianSDK.so")
H, S, U = ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint32

lib.ZL_Create.restype = H
lib.ZL_SetConfig.argtypes = [H, S]
lib.ZL_CardLogin.argtypes = [H, S]
lib.ZL_GetResult.argtypes = [H, S, U]
lib.ZL_GetLastErrorMessage.argtypes = [H, S, U]
lib.ZL_SetAutoHeartbeat.argtypes = [H, ctypes.c_int, ctypes.c_int]
lib.ZL_Destroy.argtypes = [H]

h = lib.ZL_Create()
print("SetConfig =", lib.ZL_SetConfig(h, b"粘贴 product_token"))
print("CardLogin =", lib.ZL_CardLogin(h, b"你的卡密"))

buf = ctypes.create_string_buffer(65536)
lib.ZL_GetResult(h, buf, 65536)
print(buf.value.decode("utf-8", "replace"))

lib.ZL_SetAutoHeartbeat(h, 1, 0)
# ... 业务 ...
lib.ZL_Destroy(h)
现象原因解决
cannot open shared object file找不到 .so放程序同目录 + rpath,或 LD_LIBRARY_PATH,或装到 /usr/local/lib 后 ldconfig
wrong ELF class32 位程序加载 64 位 .so本包只有 x86_64,需用 64 位程序
version GLIBC_2.28 not found系统 glibc 太老本包要求 glibc ≥ 2.17
改名后加载失败SONAME 固定保持文件名 libZhilianSDK.so
同一台机器双系统会被当成两台设备。Windows 与 Linux 的机器码来源不同,客户同时发两个版本时,后台要按两台设备处理;要复用同一张卡,先解绑或转绑。

13其他语言

Go、Java、JavaScript / TypeScript、PHP、Rust、Kotlin、Swift、Zig、Nim、Lua、PureBasic、aardio、按键精灵、懒人精灵等使用 协议源码示例:直接实现 /api/open 的签名、加密与调用,不依赖 DLL。完整清单、依赖与实测状态见 多语言源码清单。

语言示例入口运行
Gogo/main.gogo mod tidy && go run .
Javajava/ZhiLianClient.javajava ZhiLianClient.java
JavaScript / TSjavascript-typescript/zhilian.jsnode zhilian.js
PHPphp/zhilian.phpphp zhilian.php
C#(协议版)C#/ZhiLianClient.csdotnet run
Rustrust/cargo run --release
Kotlinkotlin/gradle run
Swiftswift/swift run
Zigzig/main.zigzig run main.zig
Nimnim/zhilian.nimnim c -d:release -r zhilian.nim
Lualua/zhilian.lualua zhilian.lua
易语言 / 按键 / 懒人 / aardio / PureBasic对应目录见目录内说明或 源码清单

这些示例顶部的配置区需要填:BASE_URL、APP_UUID、APP_SECRET(或 Ed25519 公钥)、AES_KEY_HEX、CHACHA_KEY_HEX、ALGORITHM、SIGN_SCHEME。参数全部来自后台「导出密钥」。

14接口清单

SDK 共 64 个导出函数 / 34 个业务接口。下面是最常用的部分;完整列表见 SDK 原始文档 与 API 加密文档。

分类函数说明
生命周期ZL_Create / ZL_Destroy、ZL_SetConfig、ZL_SetAutoHeartbeat创建、配置、销毁、自动心跳
登录ZL_CardLogin、ZL_AccountLogin、ZL_DeviceTrialLogin、ZL_Logout卡密 / 账号 / 设备试用 / 退出
账号ZL_UserRegister、ZL_Recharge、ZL_SendEmailCode、ZL_ClaimTrial、ZL_ResetPassword、ZL_UpdatePassword、ZL_ChangeBind注册、充值、验证码、试用、改密、转绑
查询ZL_GetNotice、ZL_GetUpdateUrl、ZL_CheckVersion、ZL_GetCardInfo、ZL_GetExpire、ZL_Heartbeat公告、更新、版本、卡密、到期、心跳
数据ZL_GetAppData、ZL_GetVariable、ZL_ExecuteFunction、ZL_GetUserData、ZL_SetUserData、ZL_PointsDeduct、ZL_PointsQuery、ZL_ExecuteLua程序数据、变量、远程函数、云数据、点数、LUA
授权 / 支付ZL_WinLicense、ZL_VMPLicense、ZL_OnlinePay、ZL_Call(h, 38, "{}")WinLicense、VMP、在线支付、VMP 成品授权
工具ZL_GetResult、ZL_GetLastError、ZL_GetLastErrorMessage、ZL_GetState、ZL_GetToken、ZL_GetMachineId取结果、错误、状态、token、机器码
接口 23 / 24 / 25(封停用户、加黑名单、扣时间)属于管理操作,服务端禁止客户端调用,请在后台操作。

15返回值与错误码

返回值含义处理
0成功用 ZL_GetResult 取数据
> 0服务端业务错误(卡号不存在、账号已到期等)用 ZL_GetLastErrorMessage 取中文提示
< 0SDK 层错误(网络、配置、验签等)见下表
值常量含义
-1ZL_ERR_INVALID_HANDLE句柄无效,检查是否已销毁
-2ZL_ERR_INVALID_ARG参数不合法(对接串被改过等)
-3ZL_ERR_NOT_CONFIGURED配置不完整,错误信息会写明缺哪个字段
-4ZL_ERR_NETWORK连不上服务器,检查地址、端口、防火墙
-5ZL_ERR_TIMEOUT请求超时
-6ZL_ERR_HTTPHTTP 层错误
-7ZL_ERR_JSON响应格式异常
-8ZL_ERR_CRYPTO加解密失败(密钥不对)
-9ZL_ERR_BUFFER_SMALL缓冲区太小
-10ZL_ERR_INTERNAL内部错误
-11ZL_ERR_NOT_LOGGED_IN未登录就调用需要登录的接口
-12ZL_ERR_SESSION_EXPIRED会话失效,需要重新登录
-13ZL_ERR_SIGN_VERIFY响应验签失败(公钥不匹配或被篡改)
-14ZL_ERR_MACHINE_CODE机器码生成失败

16机器码

SDK 自动采集硬件信息并生成 32 位大写 MD5,可用 ZL_GetMachineId 取。不同环境(虚拟机、云主机、精简系统)可能取不到某些项,可以换规则:

规则采集项适用场景
1CPU + 主板 UUID + 磁盘 + 主板序列号 + MAC最严格,换网卡会变
2CPU + 主板 UUID + 磁盘 + 主板序列号默认,稳定性最好
3磁盘 + 主板序列号CPU 等信息取不到时
4仅 CPU虚拟机环境
5仅磁盘换硬件频繁时
6仅 MAC特殊场景
规则一旦上线不要随便改。换了规则机器码就变了,老用户会被判定成新机器,需要重新绑定。

17常见问题

加载 DLL 报 0xC0000135 / 找不到模块?

  • DLL 没放在 exe 同目录,或不在程序搜索路径;
  • 位数不匹配:32 位程序加载了 x64 DLL,或反过来。

Linux 上加载 .so 失败?

cannot open shared object file → 找不到文件,放同目录 + rpath;wrong ELF class → 位数不对;GLIBC_2.xx not found → 系统 glibc 太老(要求 ≥ 2.17)。

返回 -3,说「缺少 xxx」?

配置不完整。用对接串一般不会出现;逐项设置时按错误信息补字段。

返回 -13 验签失败?

三种可能:对接串是别人的密钥、服务器地址连到了另一个站、中间有代理改包。先核对对接串与服务器。

中文显示乱码?

接口返回 UTF-8。易语言 / VB6 用 ZL_Utf8ToAnsi;Python 用 .decode("utf-8");C# 用 Encoding.UTF8.GetString。

要不要自己开心跳?

建议开:ZL_SetAutoHeartbeat(h, 1, 0)。默认关闭,不开长时间在线可能被判定掉线;interval=0 自动跟随服务端周期。

多线程能共用一个句柄吗?

SDK 内部有锁,不会崩,但 ZL_GetResult 会互相覆盖。推荐每个线程独立 ZL_Create。

挑战码要处理吗?

不用。SDK 默认自动判断:后台开公开效验就自动申请并带上,没开就不发。除非手动 ZL_SetChallengeMode(h, 0) 关闭。

WinLicense / VMP 授权怎么用?

登录成功后调 ZL_WinLicense(接口 26)或 ZL_VMPLicense(接口 36),把返回的授权数据交给对应加壳工具。

能不能做成单文件,不单独带 DLL?

可以:资源嵌入 + 运行时释放再加载(最稳);或用打包工具虚拟进 exe;MemoryModule 内存加载对 VMProtect 加壳的 DLL 兼容性差,需实测。随包的 .lib 是导入库,不是静态库。

18注意事项

  • 位数必须匹配:32 位用 x86,64 位用 x64;Linux 只有 x86_64。
  • Windows DLL 默认放 exe 同目录;Linux .so 放同目录并加 -Wl,-rpath,'$ORIGIN'。
  • 用完必须 ZL_Destroy,否则心跳线程不退出。
  • 句柄不要跨进程 / 跨模块传递,只在当前进程有效。
  • 字符串统一 UTF-8,GBK 环境记得转码。
  • 缓冲区建议 ≥ 64 KB。
  • product_token 是敏感信息,不要明文放在会被别人看到的地方。
  • 要加壳(VMProtect / WinLicense)时,先完成接入调试,再加壳。
开始接入

下载完整 SDK,按本教程 3 步跑通登录;遇到问题带上 ZL_GetLastErrorMessage 的输出到售后群。