01这是什么
智链系统 SDK 是智链网络验证的客户端 SDK:Windows 下是 DLL,Linux 下是 .so,两个平台的函数名、参数、返回值完全一致。你的程序只要调用它,就能完成卡密登录、账号登录、到期检测、点数扣减、远程变量与云函数等流程。
- 登录验证:卡密登录、账号密码登录、设备试用登录
- 状态维护:心跳保活、到期时间、账号状态
- 账号体系:注册、充值、改密、找回密码、转绑
- 数据交互:公告、远程变量、远程函数、账号云数据、点数
- 加壳配套:WinLicense 授权、VMP 授权码
02两种接入方式
| 方式 | 适合 | 入口 | 难度 |
|---|---|---|---|
| 原生 SDK | 桌面程序:C/C++、C#、Python、易语言、Delphi、VB6 | ZhilianSDK_x64.dll / libZhilianSDK.so,三行调用 | 最低 |
| 协议源码 | Web、服务端、脚本、跨平台程序 | POST /api/open,21 种语言示例 | 中等 |
两种方式共用同一个应用、同一套卡密与授权数据,可以混用:桌面端用原生 SDK,服务端用协议源码,登录 token 与用户体系是同一套。
03目录与下载
| 文件 / 目录 | 用途 |
|---|---|
Zhi_Liani_SDK/Win_SDK/ZhilianSDK_x64.dll | 64 位程序主文件,放 exe 同目录 |
Zhi_Liani_SDK/Win_SDK/ZhilianSDK_x86.dll | 32 位程序(易语言、VB6、Delphi 32 位) |
Zhi_Liani_SDK/Win_SDK/*.lib | C/C++ 导入库,仅静态链接时需要 |
Zhi_Liani_SDK/Win_SDK/ZhilianSDK.h | C/C++ 头文件,函数原型与错误码 |
Zhi_Liani_SDK/Linux_SDK/libZhilianSDK.so | Linux x86_64 全部内容,单文件 |
python/ go/ java/ C#/ C/ C++/ … | 21 种语言的协议源码示例 |
Zhi_Liani_SDK/ZhilianSDK_接入文档.html | SDK 原始接入文档(本页的精简来源) |
0xC0000135。045 分钟接入
拿到对接参数
登录验证后台 → 进入应用 → 点「一键生成对接参数」→ 复制整串加密文本(product_token)。这串内容已经包含服务器地址、应用 UUID、加密密钥、验签公钥与算法,不需要再手填。
把库放到程序目录
Windows:把 ZhilianSDK_x64.dll 或 ZhilianSDK_x86.dll 放到 exe 旁边。
Linux:把 libZhilianSDK.so 放程序同目录,编译时加 -Wl,-rpath,'$ORIGIN'。
三步调用
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_SetSecret | Ed25519 验签公钥(方案 1)或对称 Secret(方案 0) | 是 |
ZL_SetKeys | AES 与 ChaCha20 密钥(64 位 hex) | 按算法 |
ZL_SetCrypto | algorithm: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);
}
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#/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)
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 (句柄)
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 class | 32 位程序加载 64 位 .so | 本包只有 x86_64,需用 64 位程序 |
version GLIBC_2.28 not found | 系统 glibc 太老 | 本包要求 glibc ≥ 2.17 |
| 改名后加载失败 | SONAME 固定 | 保持文件名 libZhilianSDK.so |
13其他语言
Go、Java、JavaScript / TypeScript、PHP、Rust、Kotlin、Swift、Zig、Nim、Lua、PureBasic、aardio、按键精灵、懒人精灵等使用 协议源码示例:直接实现 /api/open 的签名、加密与调用,不依赖 DLL。完整清单、依赖与实测状态见 多语言源码清单。
| 语言 | 示例入口 | 运行 |
|---|---|---|
| Go | go/main.go | go mod tidy && go run . |
| Java | java/ZhiLianClient.java | java ZhiLianClient.java |
| JavaScript / TS | javascript-typescript/zhilian.js | node zhilian.js |
| PHP | php/zhilian.php | php zhilian.php |
| C#(协议版) | C#/ZhiLianClient.cs | dotnet run |
| Rust | rust/ | cargo run --release |
| Kotlin | kotlin/ | gradle run |
| Swift | swift/ | swift run |
| Zig | zig/main.zig | zig run main.zig |
| Nim | nim/zhilian.nim | nim c -d:release -r zhilian.nim |
| Lua | lua/zhilian.lua | lua 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、机器码 |
15返回值与错误码
| 返回值 | 含义 | 处理 |
|---|---|---|
0 | 成功 | 用 ZL_GetResult 取数据 |
> 0 | 服务端业务错误(卡号不存在、账号已到期等) | 用 ZL_GetLastErrorMessage 取中文提示 |
< 0 | SDK 层错误(网络、配置、验签等) | 见下表 |
| 值 | 常量 | 含义 |
|---|---|---|
| -1 | ZL_ERR_INVALID_HANDLE | 句柄无效,检查是否已销毁 |
| -2 | ZL_ERR_INVALID_ARG | 参数不合法(对接串被改过等) |
| -3 | ZL_ERR_NOT_CONFIGURED | 配置不完整,错误信息会写明缺哪个字段 |
| -4 | ZL_ERR_NETWORK | 连不上服务器,检查地址、端口、防火墙 |
| -5 | ZL_ERR_TIMEOUT | 请求超时 |
| -6 | ZL_ERR_HTTP | HTTP 层错误 |
| -7 | ZL_ERR_JSON | 响应格式异常 |
| -8 | ZL_ERR_CRYPTO | 加解密失败(密钥不对) |
| -9 | ZL_ERR_BUFFER_SMALL | 缓冲区太小 |
| -10 | ZL_ERR_INTERNAL | 内部错误 |
| -11 | ZL_ERR_NOT_LOGGED_IN | 未登录就调用需要登录的接口 |
| -12 | ZL_ERR_SESSION_EXPIRED | 会话失效,需要重新登录 |
| -13 | ZL_ERR_SIGN_VERIFY | 响应验签失败(公钥不匹配或被篡改) |
| -14 | ZL_ERR_MACHINE_CODE | 机器码生成失败 |
16机器码
SDK 自动采集硬件信息并生成 32 位大写 MD5,可用 ZL_GetMachineId 取。不同环境(虚拟机、云主机、精简系统)可能取不到某些项,可以换规则:
| 规则 | 采集项 | 适用场景 |
|---|---|---|
| 1 | CPU + 主板 UUID + 磁盘 + 主板序列号 + MAC | 最严格,换网卡会变 |
| 2 | CPU + 主板 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 的输出到售后群。