[C++] 纯文本查看 复制代码
/******************************************************************************
* WLKeygen.c -- WinLicense 授权密钥生成器 (纯 Win32 API) [修复版]
*
* 作者环境: Visual Studio 2013 / MSVC / Win32 或 x64
* 依赖: WinLicenseSDK.h + WinLicenseSDK32.lib / WinLicenseSDK64.lib
*
* 本版修复:
* 1) 「无限制」必须传 0,不能传 wlPermKey(-1) —— 这是"永远提示到期"的根因
* 2) 输出缓冲区未清零 + 未按返回长度截断 —— 重复生成时旧内容残留
* 3) 单行 EDIT 缺少 ES_AUTOHSCROLL —— 输入长度被可见宽度卡死
* 4) 注册表主键/路径拼接规范化,默认值改为 HKEY_LOCAL_MACHINE\Software\MyCompany\MyProduct
* 5) 日期选择器改用 DTS_SHOWNONE,可显式表示"不设日期限制"
* 6) ANSI / UNICODE 单选按钮真正生效
******************************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "WinLicenseSDK.h"
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "comdlg32.lib")
#pragma comment(lib, "advapi32.lib")
/* -------- 控件 ID -------- */
#define IDC_CMB_HASH 1001
#define IDC_RADIO_ANSI 1002
#define IDC_RADIO_UNICODE 1003
#define IDC_EDIT_NAME 1010
#define IDC_EDIT_COMPANY 1011
#define IDC_EDIT_CUSTOM 1012
#define IDC_EDIT_MACHINE 1013
#define IDC_EDIT_DAYS 1020
#define IDC_EDIT_EXEC 1021
#define IDC_DATE_EXP 1022
#define IDC_CHK_TIMECTRL 1023
#define IDC_LIST_TEXTKEY 1030
#define IDC_LIST_SMARTKEY 1031
#define IDC_EDIT_REG_MAIN 1040
#define IDC_EDIT_REG_PATH 1041
#define IDC_EDIT_REG_VALUE 1042
#define IDC_EDIT_REG_FILE 1043
#define IDC_EDIT_FILE_NAME 1044
#define IDC_BTN_GEN_TEXT 1050
#define IDC_BTN_GEN_SMART 1051
#define IDC_BTN_GEN_REGFILE 1052
#define IDC_BTN_GEN_FILEKEY 1053
/* -------- 缓冲区大小 -------- */
#define HASH_BUF_SIZE 16384 /* LicenseHash XML 约 3500+ 字节, 留足余量 */
#define OUT_BUF_SIZE 32768 /* 输出缓冲: 文件密钥/注册表文件可能较大 */
#define EDIT_LIMIT 4096 /* 单行编辑框最大输入字符数 */
/* 关键常量: WinLicense 生成类 API 里 "不使用该项限制" 一律传 0
wlPermKey(-1) 只是 WLRegDaysLeft() 之类【查询】函数的返回值含义,
绝对不能当作生成参数传进去 */
#define WL_NO_LIMIT 0
/* -------- 全局句柄 -------- */
static HINSTANCE g_hInst;
static HFONT g_hFont;
/* -------- 静态大缓冲(单线程 UI, 避免爆栈) -------- */
static char g_hashA[HASH_BUF_SIZE];
static wchar_t g_hashW[HASH_BUF_SIZE];
static char g_outA[OUT_BUF_SIZE];
static wchar_t g_outW[OUT_BUF_SIZE];
static char g_dispA[OUT_BUF_SIZE * 2];
static wchar_t g_dispW[OUT_BUF_SIZE * 2];
/* ============================================================
* 小工具
* ============================================================ */
static void GetText(HWND hDlg, int id, char* buf, int cap)
{
buf[0] = 0;
GetDlgItemTextA(hDlg, id, buf, cap);
}
static void GetTextW(HWND hDlg, int id, wchar_t* buf, int cap)
{
buf[0] = 0;
GetDlgItemTextW(hDlg, id, buf, cap);
}
static int GetInt(HWND hDlg, int id, int defv)
{
char b[32];
GetText(hDlg, id, b, sizeof(b));
if (b[0] == 0) return defv;
return atoi(b);
}
static BOOL IsUnicodeMode(HWND hDlg)
{
return IsDlgButtonChecked(hDlg, IDC_RADIO_UNICODE) == BST_CHECKED;
}
/* -------- 读取 Hash 文件内容 (ANSI) -------- */
static int LoadHashFromFile(const char* filename, char* buf, int cap)
{
FILE* f;
int n;
buf[0] = 0;
f = fopen(filename, "rb");
if (!f) return 0;
n = (int)fread(buf, 1, cap - 1, f);
fclose(f);
if (n <= 0) return 0;
buf[n] = 0;
/* 跳过 UTF-8 BOM (记事本保存时可能带) */
if (n >= 3 &&
(unsigned char)buf[0] == 0xEF &&
(unsigned char)buf[1] == 0xBB &&
(unsigned char)buf[2] == 0xBF)
{
memmove(buf, buf + 3, n - 3 + 1);
n -= 3;
}
/* 去掉末尾换行/回车/空格/制表符 */
while (n > 0 && (buf[n - 1] == '\r' || buf[n - 1] == '\n' ||
buf[n - 1] == ' ' || buf[n - 1] == '\t'))
buf[--n] = 0;
return n > 0;
}
/* -------- 从下拉框读取 hash 文件名,再读取文件内容 -------- */
static int GetHashContent(HWND hDlg)
{
char fname[MAX_PATH];
ZeroMemory(g_hashA, sizeof(g_hashA));
ZeroMemory(g_hashW, sizeof(g_hashW));
GetText(hDlg, IDC_CMB_HASH, fname, sizeof(fname));
if (fname[0] == 0)
{
MessageBoxA(hDlg, "请先选择或填写 LicenseHash 文件名。",
"缺少 Hash 文件", MB_ICONWARNING);
return 0;
}
if (!LoadHashFromFile(fname, g_hashA, HASH_BUF_SIZE))
{
MessageBoxA(hDlg,
"无法读取 LicenseHash 文件,请确认:\n"
"1. 文件与程序在同一目录,或填写了完整路径\n"
"2. 文件内容为完整 Hash XML 字符串(非空)",
"读取失败", MB_ICONWARNING);
return 0;
}
/* Hash 本身是 ASCII, 直接转宽字符供 W 版 API 使用 */
MultiByteToWideChar(CP_ACP, 0, g_hashA, -1, g_hashW, HASH_BUF_SIZE);
return 1;
}
/* -------- 安全写文件 -------- */
static void WriteFile2(const char* path, const void* buf, int len)
{
FILE* f = fopen(path, "wb");
if (f)
{
fwrite(buf, 1, (size_t)len, f);
fclose(f);
}
else
{
char msg[MAX_PATH + 64];
_snprintf(msg, sizeof(msg), "无法写入文件:%s", path);
msg[sizeof(msg) - 1] = 0;
MessageBoxA(NULL, msg, "写文件失败", MB_ICONWARNING);
}
}
/* -------- 把 \n 补成 \r\n 并填入多行 EDIT (ANSI) -------- */
static void SetMultiTextA(HWND hDlg, int id, const char* s)
{
int i = 0, j = 0;
int cap = (int)sizeof(g_dispA) - 3;
SetDlgItemTextA(hDlg, id, ""); /* 先彻底清空 */
while (s[i] && j < cap)
{
if (s[i] == '\n' && (i == 0 || s[i - 1] != '\r'))
{
g_dispA[j++] = '\r';
g_dispA[j++] = '\n';
}
else
g_dispA[j++] = s[i];
i++;
}
g_dispA[j] = 0;
SetDlgItemTextA(hDlg, id, g_dispA);
}
/* -------- 同上, 宽字符版 -------- */
static void SetMultiTextW(HWND hDlg, int id, const wchar_t* s)
{
int i = 0, j = 0;
int cap = (int)(sizeof(g_dispW) / sizeof(wchar_t)) - 3;
SetDlgItemTextW(hDlg, id, L"");
while (s[i] && j < cap)
{
if (s[i] == L'\n' && (i == 0 || s[i - 1] != L'\r'))
{
g_dispW[j++] = L'\r';
g_dispW[j++] = L'\n';
}
else
g_dispW[j++] = s[i];
i++;
}
g_dispW[j] = 0;
SetDlgItemTextW(hDlg, id, g_dispW);
}
/* -------- 按 SDK 返回长度做安全截断 -------- */
static void TerminateA(char* buf, int cap, int ret)
{
if (ret > 0 && ret < cap) buf[ret] = 0;
buf[cap - 1] = 0;
}
static void TerminateW(wchar_t* buf, int cap, int ret)
{
/* ret 可能是字符数也可能是字节数, 两种都截一下, 取先出现的 0 */
if (ret > 0 && ret < cap) buf[ret] = 0;
if (ret > 0 && (ret / 2) < cap) buf[cap - 1] = 0;
buf[cap - 1] = 0;
}
/* -------- 启用/禁用 到期时间相关控件 -------- */
static void EnableTimeControls(HWND hWnd, BOOL bEnable)
{
EnableWindow(GetDlgItem(hWnd, IDC_EDIT_DAYS), bEnable);
EnableWindow(GetDlgItem(hWnd, IDC_EDIT_EXEC), bEnable);
EnableWindow(GetDlgItem(hWnd, IDC_DATE_EXP), bEnable);
}
/* ============================================================
* 组装到期参数 —— 核心修复点
*
* 不勾选 = 永久密钥 = 天数/次数/运行时长/累计分钟全部传 0, 日期传 NULL
* 勾选 = 只把用户真正填了的项传进去, 其余仍然传 0
* ============================================================ */
static void BuildExpiration(HWND hDlg, int* pDays, int* pExec,
int* pRuntime, int* pGlobalMin,
SYSTEMTIME* pDate, SYSTEMTIME** ppDateArg)
{
*pDays = WL_NO_LIMIT;
*pExec = WL_NO_LIMIT;
*pRuntime = WL_NO_LIMIT;
*pGlobalMin = WL_NO_LIMIT;
*ppDateArg = NULL;
if (IsDlgButtonChecked(hDlg, IDC_CHK_TIMECTRL) != BST_CHECKED)
return; /* 永久密钥, 直接返回 */
*pDays = GetInt(hDlg, IDC_EDIT_DAYS, 0);
*pExec = GetInt(hDlg, IDC_EDIT_EXEC, 0);
if (*pDays < 0) *pDays = WL_NO_LIMIT;
if (*pExec < 0) *pExec = WL_NO_LIMIT;
ZeroMemory(pDate, sizeof(SYSTEMTIME));
/* 日期控件带 DTS_SHOWNONE: 未勾选返回 GDT_NONE, 表示不设日期限制 */
if (DateTime_GetSystemtime(GetDlgItem(hDlg, IDC_DATE_EXP), pDate) == GDT_VALID)
{
/* 只保留日期部分, 时间归零, 避免"今天已过期"的边界问题 */
pDate->wHour = 0;
pDate->wMinute = 0;
pDate->wSecond = 0;
pDate->wMilliseconds = 0;
*ppDateArg = pDate;
}
}
/* -------- 生成失败时的统一提示 -------- */
static void ShowFail(HWND hDlg, const char* what, int ret)
{
char msg[512];
_snprintf(msg, sizeof(msg),
"%s生成失败 (SDK 返回值 = %d)。\n\n"
"排查建议:\n"
"1. LicenseHash 文件内容是否为完整、未被截断的 XML\n"
"2. Hash 是否与目标程序保护时使用的项目一致\n"
"3. 若 WinLicense 项目里勾选了「密钥必须绑定硬件码 / 必须带到期」,\n"
" 则对应输入项不能为空", what, ret);
msg[sizeof(msg) - 1] = 0;
MessageBoxA(hDlg, msg, "生成失败", MB_ICONWARNING);
}
/* -------- 注册表主键 + 路径 规范拼接 -------- */
static void JoinRegKeyA(char* dst, int cap, const char* mainKey, const char* path)
{
char m[256];
int n;
_snprintf(m, sizeof(m), "%s", mainKey ? mainKey : "");
m[sizeof(m) - 1] = 0;
n = (int)strlen(m);
while (n > 0 && (m[n - 1] == '\\' || m[n - 1] == ' ')) m[--n] = 0;
while (*path == '\\' || *path == ' ') path++;
if (m[0] == 0)
_snprintf(dst, cap, "%s", path);
else if (path[0] == 0)
_snprintf(dst, cap, "%s", m);
else
_snprintf(dst, cap, "%s\\%s", m, path);
dst[cap - 1] = 0;
/* 去掉可能的尾部反斜杠 */
n = (int)strlen(dst);
while (n > 0 && dst[n - 1] == '\\') dst[--n] = 0;
}
/* ============================================================
* 四个生成动作
* ============================================================ */
/* 1) 文本密钥 */
static void OnGenText(HWND hDlg)
{
char nameA[512], compA[512], customA[512], machineA[512];
wchar_t nameW[512], compW[512], customW[512], machineW[512];
int days, exec, runtime, globalMin, ret;
SYSTEMTIME date, *pDate;
if (!GetHashContent(hDlg)) return;
BuildExpiration(hDlg, &days, &exec, &runtime, &globalMin, &date, &pDate);
ZeroMemory(g_outA, sizeof(g_outA));
ZeroMemory(g_outW, sizeof(g_outW));
if (IsUnicodeMode(hDlg))
{
GetTextW(hDlg, IDC_EDIT_NAME, nameW, 512);
GetTextW(hDlg, IDC_EDIT_COMPANY, compW, 512);
GetTextW(hDlg, IDC_EDIT_CUSTOM, customW, 512);
GetTextW(hDlg, IDC_EDIT_MACHINE, machineW, 512);
ret = WLGenLicenseTextKeyW(g_hashW, nameW, compW, customW,
machineW[0] ? machineW : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin, g_outW);
TerminateW(g_outW, OUT_BUF_SIZE, ret);
if (ret > 0 && g_outW[0])
SetMultiTextW(hDlg, IDC_LIST_TEXTKEY, g_outW);
else
ShowFail(hDlg, "文本密钥", ret);
}
else
{
GetText(hDlg, IDC_EDIT_NAME, nameA, sizeof(nameA));
GetText(hDlg, IDC_EDIT_COMPANY, compA, sizeof(compA));
GetText(hDlg, IDC_EDIT_CUSTOM, customA, sizeof(customA));
GetText(hDlg, IDC_EDIT_MACHINE, machineA, sizeof(machineA));
ret = WLGenLicenseTextKey(g_hashA, nameA, compA, customA,
machineA[0] ? machineA : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin, g_outA);
TerminateA(g_outA, OUT_BUF_SIZE, ret);
if (ret > 0 && g_outA[0])
SetMultiTextA(hDlg, IDC_LIST_TEXTKEY, g_outA);
else
ShowFail(hDlg, "文本密钥", ret);
}
}
/* 2) 智能激活密钥 */
static void OnGenSmart(HWND hDlg)
{
char nameA[512], compA[512], customA[512], machineA[512];
wchar_t nameW[512], compW[512], customW[512], machineW[512];
int days, exec, runtime, globalMin, ret;
SYSTEMTIME date, *pDate;
if (!GetHashContent(hDlg)) return;
BuildExpiration(hDlg, &days, &exec, &runtime, &globalMin, &date, &pDate);
ZeroMemory(g_outA, sizeof(g_outA));
ZeroMemory(g_outW, sizeof(g_outW));
if (IsUnicodeMode(hDlg))
{
GetTextW(hDlg, IDC_EDIT_NAME, nameW, 512);
GetTextW(hDlg, IDC_EDIT_COMPANY, compW, 512);
GetTextW(hDlg, IDC_EDIT_CUSTOM, customW, 512);
GetTextW(hDlg, IDC_EDIT_MACHINE, machineW, 512);
ret = WLGenLicenseSmartKeyW(g_hashW, nameW, compW, customW,
machineW[0] ? machineW : NULL,
days, exec, pDate, g_outW);
TerminateW(g_outW, OUT_BUF_SIZE, ret);
if (ret > 0 && g_outW[0])
SetMultiTextW(hDlg, IDC_LIST_SMARTKEY, g_outW);
else
ShowFail(hDlg, "智能激活密钥", ret);
}
else
{
GetText(hDlg, IDC_EDIT_NAME, nameA, sizeof(nameA));
GetText(hDlg, IDC_EDIT_COMPANY, compA, sizeof(compA));
GetText(hDlg, IDC_EDIT_CUSTOM, customA, sizeof(customA));
GetText(hDlg, IDC_EDIT_MACHINE, machineA, sizeof(machineA));
ret = WLGenLicenseSmartKey(g_hashA, nameA, compA, customA,
machineA[0] ? machineA : NULL,
days, exec, pDate, g_outA);
TerminateA(g_outA, OUT_BUF_SIZE, ret);
if (ret > 0 && g_outA[0])
SetMultiTextA(hDlg, IDC_LIST_SMARTKEY, g_outA);
else
ShowFail(hDlg, "智能激活密钥", ret);
}
}
/* 3) 注册表密钥文件 (.reg) */
static void OnGenRegFile(HWND hDlg)
{
char nameA[512], compA[512], customA[512], machineA[512];
wchar_t nameW[512], compW[512], customW[512], machineW[512];
char regMain[256], regPath[512], regValue[256], regFile[MAX_PATH];
char keyNameA[768];
wchar_t keyNameW[768], regValueW[256];
int days, exec, runtime, globalMin, ret;
SYSTEMTIME date, *pDate;
if (!GetHashContent(hDlg)) return;
GetText(hDlg, IDC_EDIT_REG_MAIN, regMain, sizeof(regMain));
GetText(hDlg, IDC_EDIT_REG_PATH, regPath, sizeof(regPath));
GetText(hDlg, IDC_EDIT_REG_VALUE, regValue, sizeof(regValue));
GetText(hDlg, IDC_EDIT_REG_FILE, regFile, sizeof(regFile));
BuildExpiration(hDlg, &days, &exec, &runtime, &globalMin, &date, &pDate);
if (regValue[0] == 0)
{
MessageBoxA(hDlg, "请填写键值名(例如 license)。", "缺少键值名", MB_ICONWARNING);
return;
}
JoinRegKeyA(keyNameA, sizeof(keyNameA), regMain, regPath);
MultiByteToWideChar(CP_ACP, 0, keyNameA, -1, keyNameW, 768);
MultiByteToWideChar(CP_ACP, 0, regValue, -1, regValueW, 256);
ZeroMemory(g_outA, sizeof(g_outA));
if (IsUnicodeMode(hDlg))
{
GetTextW(hDlg, IDC_EDIT_NAME, nameW, 512);
GetTextW(hDlg, IDC_EDIT_COMPANY, compW, 512);
GetTextW(hDlg, IDC_EDIT_CUSTOM, customW, 512);
GetTextW(hDlg, IDC_EDIT_MACHINE, machineW, 512);
ret = WLGenLicenseRegistryKeyW(g_hashW, nameW, compW, customW,
machineW[0] ? machineW : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin,
keyNameW, regValueW, g_outA);
}
else
{
GetText(hDlg, IDC_EDIT_NAME, nameA, sizeof(nameA));
GetText(hDlg, IDC_EDIT_COMPANY, compA, sizeof(compA));
GetText(hDlg, IDC_EDIT_CUSTOM, customA, sizeof(customA));
GetText(hDlg, IDC_EDIT_MACHINE, machineA, sizeof(machineA));
ret = WLGenLicenseRegistryKey(g_hashA, nameA, compA, customA,
machineA[0] ? machineA : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin,
keyNameA, regValue, g_outA);
}
if (ret > 0)
{
char msg[MAX_PATH + 768];
if (regFile[0])
WriteFile2(regFile, g_outA, ret);
_snprintf(msg, sizeof(msg),
"注册表密钥文件已生成。\n\n位置:%s\n键值名:%s\n输出文件:%s",
keyNameA, regValue, regFile[0] ? regFile : "(未指定)");
msg[sizeof(msg) - 1] = 0;
MessageBoxA(hDlg, msg, "完成", MB_ICONINFORMATION);
}
else
ShowFail(hDlg, "注册表密钥", ret);
}
/* 4) 文件密钥 (.dat) */
static void OnGenFileKey(HWND hDlg)
{
char nameA[512], compA[512], customA[512], machineA[512];
wchar_t nameW[512], compW[512], customW[512], machineW[512];
char fileName[MAX_PATH];
int days, exec, runtime, globalMin, ret;
SYSTEMTIME date, *pDate;
if (!GetHashContent(hDlg)) return;
GetText(hDlg, IDC_EDIT_FILE_NAME, fileName, sizeof(fileName));
BuildExpiration(hDlg, &days, &exec, &runtime, &globalMin, &date, &pDate);
ZeroMemory(g_outA, sizeof(g_outA));
if (IsUnicodeMode(hDlg))
{
GetTextW(hDlg, IDC_EDIT_NAME, nameW, 512);
GetTextW(hDlg, IDC_EDIT_COMPANY, compW, 512);
GetTextW(hDlg, IDC_EDIT_CUSTOM, customW, 512);
GetTextW(hDlg, IDC_EDIT_MACHINE, machineW, 512);
ret = WLGenLicenseFileKeyW(g_hashW, nameW, compW, customW,
machineW[0] ? machineW : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin, g_outA);
}
else
{
GetText(hDlg, IDC_EDIT_NAME, nameA, sizeof(nameA));
GetText(hDlg, IDC_EDIT_COMPANY, compA, sizeof(compA));
GetText(hDlg, IDC_EDIT_CUSTOM, customA, sizeof(customA));
GetText(hDlg, IDC_EDIT_MACHINE, machineA, sizeof(machineA));
ret = WLGenLicenseFileKey(g_hashA, nameA, compA, customA,
machineA[0] ? machineA : NULL,
days, exec, pDate,
WL_NO_LIMIT, runtime, globalMin, g_outA);
}
if (ret > 0)
{
char msg[MAX_PATH + 128];
if (fileName[0])
WriteFile2(fileName, g_outA, ret);
_snprintf(msg, sizeof(msg), "文件密钥已生成(%d 字节)。\n\n输出文件:%s",
ret, fileName[0] ? fileName : "(未指定)");
msg[sizeof(msg) - 1] = 0;
MessageBoxA(hDlg, msg, "完成", MB_ICONINFORMATION);
}
else
ShowFail(hDlg, "文件密钥", ret);
}
/* ============================================================
* 控件创建辅助
* ============================================================ */
static HWND MkLabel(HWND p, const char* s, int x, int y, int w, int h)
{
HWND hw = CreateWindowExA(0, "STATIC", s, WS_CHILD | WS_VISIBLE | SS_LEFT,
x, y, w, h, p, NULL, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
return hw;
}
/* 注意: 补上 ES_AUTOHSCROLL, 否则单行 EDIT 输入到可见宽度就再也打不进字 */
static HWND MkEdit(HWND p, int id, int x, int y, int w, int h, DWORD extra)
{
HWND hw = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | extra,
x, y, w, h, p, (HMENU)(INT_PTR)id, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
SendMessage(hw, EM_SETLIMITTEXT, (WPARAM)EDIT_LIMIT, 0);
return hw;
}
static HWND MkButton(HWND p, int id, const char* s, int x, int y, int w, int h)
{
HWND hw = CreateWindowExA(0, "BUTTON", s,
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
x, y, w, h, p, (HMENU)(INT_PTR)id, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
return hw;
}
static HWND MkGroup(HWND p, const char* s, int x, int y, int w, int h)
{
HWND hw = CreateWindowExA(0, "BUTTON", s,
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
x, y, w, h, p, NULL, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
return hw;
}
/* ============================================================
* 创建全部控件
* ============================================================ */
static void CreateControls(HWND hWnd)
{
HWND hw;
/* ---- 顶部: Licensehash + 授权生成类型 ---- */
MkLabel(hWnd, "选择自定义 Licensehash:", 15, 15, 160, 18);
hw = CreateWindowExA(0, "COMBOBOX", "",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_DROPDOWN | WS_VSCROLL,
180, 12, 240, 200, hWnd, (HMENU)IDC_CMB_HASH, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
SendMessageA(hw, CB_ADDSTRING, 0, (LPARAM)"Lic.txt");
SendMessageA(hw, CB_SETCURSEL, 0, 0);
MkGroup(hWnd, "授权生成类型", 440, 5, 200, 55);
hw = CreateWindowExA(0, "BUTTON", "ANSI",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP | BS_AUTORADIOBUTTON,
455, 28, 70, 20, hWnd, (HMENU)IDC_RADIO_ANSI, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
SendMessage(hw, BM_SETCHECK, BST_CHECKED, 0);
hw = CreateWindowExA(0, "BUTTON", "UNICODE",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTORADIOBUTTON,
540, 28, 90, 20, hWnd, (HMENU)IDC_RADIO_UNICODE, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
/* ---- 用户信息 ---- */
MkGroup(hWnd, "用户信息", 10, 65, 420, 165);
MkLabel(hWnd, "用户名:", 25, 92, 60, 18);
MkEdit(hWnd, IDC_EDIT_NAME, 95, 90, 320, 22, 0);
MkLabel(hWnd, "公司名:", 25, 122, 60, 18);
MkEdit(hWnd, IDC_EDIT_COMPANY, 95, 120, 320, 22, 0);
MkLabel(hWnd, "自定义:", 25, 152, 60, 18);
MkEdit(hWnd, IDC_EDIT_CUSTOM, 95, 150, 320, 22, 0);
MkLabel(hWnd, "硬件码:", 25, 182, 60, 18);
MkEdit(hWnd, IDC_EDIT_MACHINE, 95, 180, 320, 22, 0);
/* ---- 密钥到期时间 ---- */
MkGroup(hWnd, "密钥到期时间 (留空或0=不限制)", 440, 65, 200, 165);
MkLabel(hWnd, "运行天数:", 452, 92, 65, 18);
MkEdit(hWnd, IDC_EDIT_DAYS, 522, 90, 105, 22, ES_NUMBER);
MkLabel(hWnd, "运行次数:", 452, 122, 65, 18);
MkEdit(hWnd, IDC_EDIT_EXEC, 522, 120, 105, 22, ES_NUMBER);
MkLabel(hWnd, "有效期限:", 452, 152, 65, 18);
/* DTS_SHOWNONE: 日期框左侧有勾选框, 不勾 = 不设日期限制 */
hw = CreateWindowExA(0, DATETIMEPICK_CLASSA, "",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | DTS_SHORTDATEFORMAT | DTS_SHOWNONE,
522, 150, 110, 22, hWnd, (HMENU)IDC_DATE_EXP, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
DateTime_SetSystemtime(hw, GDT_NONE, NULL); /* 默认: 不设日期 */
hw = CreateWindowExA(0, "BUTTON", "启用时间控制",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX,
452, 185, 150, 20, hWnd, (HMENU)IDC_CHK_TIMECTRL, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
/* 默认不勾选, 禁用三个到期控件 */
EnableTimeControls(hWnd, FALSE);
/* ---- 文本密钥 ---- */
MkGroup(hWnd, "文本密钥", 10, 235, 210, 250);
hw = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP |
ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL,
22, 255, 186, 195, hWnd, (HMENU)IDC_LIST_TEXTKEY, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
SendMessage(hw, EM_SETLIMITTEXT, 0, 0); /* 解除多行 EDIT 的默认上限 */
MkButton(hWnd, IDC_BTN_GEN_TEXT, "生成文本密钥", 22, 455, 186, 24);
/* ---- 智能激活密钥 ---- */
MkGroup(hWnd, "智能激活密钥", 228, 235, 210, 250);
hw = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP |
ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL,
240, 255, 186, 195, hWnd, (HMENU)IDC_LIST_SMARTKEY, g_hInst, NULL);
SendMessage(hw, WM_SETFONT, (WPARAM)g_hFont, TRUE);
SendMessage(hw, EM_SETLIMITTEXT, 0, 0);
MkButton(hWnd, IDC_BTN_GEN_SMART, "生成智能密钥", 240, 455, 186, 24);
/* ---- 注册表密钥 ---- */
MkGroup(hWnd, "注册表密钥", 448, 235, 192, 200);
MkLabel(hWnd, "主键名:", 458, 258, 55, 18);
MkEdit(hWnd, IDC_EDIT_REG_MAIN, 516, 256, 115, 20, 0);
MkLabel(hWnd, "路径名:", 458, 285, 55, 18);
MkEdit(hWnd, IDC_EDIT_REG_PATH, 516, 283, 115, 20, 0);
MkLabel(hWnd, "键值名:", 458, 312, 55, 18);
MkEdit(hWnd, IDC_EDIT_REG_VALUE, 516, 310, 115, 20, 0);
MkLabel(hWnd, "文件名:", 458, 339, 55, 18);
MkEdit(hWnd, IDC_EDIT_REG_FILE, 516, 337, 115, 20, 0);
MkButton(hWnd, IDC_BTN_GEN_REGFILE, "生成注册表文件", 490, 400, 145, 24);
SetDlgItemTextA(hWnd, IDC_EDIT_REG_MAIN, "HKEY_LOCAL_MACHINE");
SetDlgItemTextA(hWnd, IDC_EDIT_REG_PATH, "Software\\MyCompany\\MyProduct");
SetDlgItemTextA(hWnd, IDC_EDIT_REG_VALUE, "license");
SetDlgItemTextA(hWnd, IDC_EDIT_REG_FILE, "WLLicenseA1.reg");
/* ---- 文件密钥 ---- */
MkGroup(hWnd, "文件密钥", 448, 440, 192, 90);
MkLabel(hWnd, "文件名:", 458, 465, 55, 18);
MkEdit(hWnd, IDC_EDIT_FILE_NAME, 516, 463, 115, 20, 0);
MkButton(hWnd, IDC_BTN_GEN_FILEKEY, "生成文件密钥", 490, 495, 145, 24);
SetDlgItemTextA(hWnd, IDC_EDIT_FILE_NAME, "WLLicenseA1.dat");
}
/* ============================================================
* 窗口过程
* ============================================================ */
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
CreateControls(hWnd);
return 0;
case WM_COMMAND:
switch (LOWORD(wp))
{
case IDC_BTN_GEN_TEXT: OnGenText(hWnd); break;
case IDC_BTN_GEN_SMART: OnGenSmart(hWnd); break;
case IDC_BTN_GEN_REGFILE: OnGenRegFile(hWnd); break;
case IDC_BTN_GEN_FILEKEY: OnGenFileKey(hWnd); break;
case IDC_CHK_TIMECTRL:
EnableTimeControls(hWnd,
IsDlgButtonChecked(hWnd, IDC_CHK_TIMECTRL) == BST_CHECKED);
break;
}
return 0;
case WM_CTLCOLORSTATIC:
SetBkMode((HDC)wp, TRANSPARENT);
return (LRESULT)GetSysColorBrush(COLOR_BTNFACE);
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcA(hWnd, msg, wp, lp);
}
/* ============================================================
* 入口
* ============================================================ */
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
{
WNDCLASSEXA wc;
HWND hWnd;
MSG msg;
INITCOMMONCONTROLSEX icc;
(void)hPrev; (void)lpCmd;
g_hInst = hInst;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_DATE_CLASSES | ICC_STANDARD_CLASSES;
InitCommonControlsEx(&icc);
g_hFont = CreateFontA(-14, 0, 0, 0, FW_NORMAL, 0, 0, 0,
GB2312_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "宋体");
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszClassName = "WLKeygenWindow";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassExA(&wc);
hWnd = CreateWindowExA(0, "WLKeygenWindow", "WinLicense 授权密钥生成器",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 670, 585,
NULL, NULL, hInst, NULL);
ShowWindow(hWnd, nShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
if (!IsDialogMessage(hWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (g_hFont) DeleteObject(g_hFont);
return (int)msg.wParam;
}