1
0
Fork 0
Co-authored-by: dengyucheng@finogeeks.com <ycdeng>
Co-authored-by: gyt-pc-12400 <gyttyg@qq.com>
master
dengyc 2022-04-13 18:22:59 -07:00 committed by GitHub
parent f051440bda
commit ba721d45cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 32080 additions and 1515 deletions

View File

@ -68,71 +68,36 @@
> 当前 Windows 版本 SDK 还在持续研发中,我们将及时同步桌面版本小程序的研发进度,如有需要请与我们联系。
## 📦 安装第三方依赖
Windows 小程序运行环境需要安装以下依赖,请提前配置环境:
- 请下载依赖包[点我下载](https://public-1251849568.cos.ap-guangzhou.myqcloud.com/sdk/lib.zip)
- 下载完后解压到vendor/finclip目录中
- 建议使用 Visual Studio 2019 版本 [点我下载](https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0)
# sdk支持状况
**注意:依赖包必须随缩主程序一同发布,并在独立目录中存放。**
| 语言 | GUI技术 | 状态 | 系统 | demo地址 | 语言库 |
|---|---|---|---|---|---|
| C++ | win32 | 测试中 | Windows | [win32](examples/win32) | 无 |
| Python | pyqt 5 | 开发中 | Windows / Mac | [Pyqt](examples/pyqt) | |
| JavaScript | Electron | 测试中 | Windows | [Electron](examples/electron) | |
解压后文件目录结构如下:
# 运行demo
```
vendor
|--finclip
| |--lib
| |--****
| |--****
| |--****
...
```
## 第一步: 下载对应的base包
根据你的系统和 架构, 下载对应的finclip-sdk
假如你是 Windows 32位, 则下载finclip-sdk-win-x86-x.y.z.zip, 并解压至vendor/win/x86目录下
### 第一步 引入头文件
```c++
#include "finclip_wrapper.h" //引入头文件
#pragma comment(lib, "FinClipSDKWrapper.lib") //引入链接库
```
## 第二步: 下载语言SDK
### 第二步 初始化SDK
部分语言, 例如python,Javascript, 我们提供了对应语言的库.
```c++
FinConfig config = {
1,
"https://api.finclip.com",
"/api/v1/mop",
"这里输入SDK KEY",
"这里输入SDK SECRET",
"",
1
};
IFinConfigPacker* configpacker = NewFinConfigPacker();
configpacker->AddConfig(config);
Initialize(hInstance, configpacker);
```
C / C++ 可以直接调用, 无须额外的库
- **SDK KEY****SDK SECRET** 可以从 [FinClip](https://finclip.com/#/home) 获取,点 [这里](https://finclip.com/#/register) 注册账号;
- 进入平台后,在「应用管理」页面添加你自己的包名后,点击「复制」即可获得 key\secret\apisever 字段;
- **apiServer****apiPrefix** 是固定字段,请直接参考本 DEMO
- **小程序 ID** 是管理后台上架的小程序 APP ID需要在「小程序管理」中创建并在「应用管理」中关联
> 小程序 ID 与 微信小程序ID 不一样哦!(这里是特指 FinClip 平台的 ID
## 第三步: 运行
根据demo文档, 将相应文件准备好后, 即可运行
# 集成
### 第三步 打开小程序
```c++
int server_type = 1;
init_finclipsdk(server_type,wappkey, wsecret);
IFinPacker* packer = NewFinPacker();
packer->BeginPacker();
packer->AddField("appId");
packer->AddValue("appId");
packer->EndPacker();
StartApplet(server_type, utf8_encode(wappid).c_str(), packer, finclip_applet_callback);
packer->Release();
```
### 查看 API 文档
您可以点击这里查看 [FinClipSDK WindowsAPI](https://docs.finogeeks.club/docs/finclip-win32/wrapper) 的开发文档

38
doc/integration.md 100644
View File

@ -0,0 +1,38 @@
# Finclip SDK的总体架构
```mermaid
flowchart LR
electron --> npm
C++ --> cpp
pyqt ---> pip
subgraph 应用
pyqt
electron
C++
end
pip --> cpp
npm --> cpp
subgraph SDK
npm
pip
cpp(c api)
end
SDK <--> 小程序进程
subgraph 小程序进程
end
```
如上图所示, Finclip SDK 的核心由 C++ 实现, 对外提供 C api, 对于部分语言, 我们根据实际情况提供了额外的库, 如 pyqt, electron 等.
对于无法直接调用C api的语言, 也可以使用dlopen等手段集成
# 集成步骤
1. 下载release包, 参考demo, 解压至相应的目录
2. 根据实际情况下载语言库和头文件, 参考demo, 解压至相应的目录
3. 根据demo和实际情况, 完成集成
# demo位置
参见首页表格
https://github.com/finogeeks/finclip-win32-demo

10
examples/README.md 100644
View File

@ -0,0 +1,10 @@
此处展示各种语言集成finclip的demo, 每个demo应完整的包含以下功能:
- 启动finclip
- 启动参数的设置
- 启动回调
- 设置窗口位置
- 自定义api
- 宿主 -> 小程序
- 宿主 -> h5
- h5 -> 宿主

View File

@ -0,0 +1,48 @@
# finclip-electron-demo
## 添加二进制依赖
下载finclip二进制包到`vendor`的对应目录下,如`vendor/win/x64`
## 快速开始
```
npm i
npm run start
```
## 调用finclip api
1. 引入finclip依赖包
注意只能在electron的主进程使用
```
const finclip = require('finclip');
```
2. 打开finclip窗口
finclipPath为finclip.exe所在位置需转换成绝对路径
```
finclip.start({
handle: 0,
finclipPath,
});
```
3. 关闭finclip窗口
```
finclip.close();
```
4. 设置finclip窗口的位置和大小
```
finclip.setPosition({ width: 800, height: 800, left: 0, top: 0 });
```
## 修改finclip依赖包
如果默认的finclip包无法满足需求可以在此项目的`src/npm`下修改并编译需要先配置C++环境

View File

@ -0,0 +1,18 @@
{
"name": "finclip-electron-demo",
"version": "1.0.0",
"description": "",
"main": "./src/main.js",
"scripts": {
"start": "npx electron ./src/main.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^18.0.0"
},
"dependencies": {
"finclip": "file:../../vendor/win/x64"
}
}

View File

@ -0,0 +1,50 @@
const { app, BrowserWindow, ipcMain } = require('electron');
const os = require('os');
const path = require('path');
const finclip = require('finclip');
const createMainWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'mainPreload.js'),
},
});
win.loadFile('../view/index.html');
};
const openFinClipWindow = () => {
const finclipPath = path.resolve(__dirname, '../../../vendor/win/x64/finclip.exe');
const result = finclip.start({
handle: 0,
finclipPath,
});
console.log(result);
};
const closeFinClipWindow = () => {
const result = finclip.close();
console.log(result);
};
ipcMain.on('OPEN_FINCLIP_WINDOW', (event, arg) => {
openFinClipWindow();
});
ipcMain.on('CLOSE_FINCLIP_WINDOW', (event, arg) => {
closeFinClipWindow();
});
ipcMain.on('SET_FINCLIP_POSITION', (event, arg) => {
const { left, top, width, height } = arg;
const result = finclip.setAppletPos({
left, top,
width, height,
});
console.log(result);
});
app.whenReady().then(() => {
createMainWindow();
});

View File

@ -0,0 +1,10 @@
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld(
'finclip',
{
open: () => ipcRenderer.send('OPEN_FINCLIP_WINDOW'),
close: () => ipcRenderer.send('CLOSE_FINCLIP_WINDOW'),
setPosition: (payload) => ipcRenderer.send('SET_FINCLIP_POSITION', payload),
}
)

View File

@ -0,0 +1,15 @@
window.openFinClipWindow = () => {
finclip.open();
};
window.closeFinClipWindow = () => {
finclip.close();
};
window.setFinClipPosition = () => {
const left = +document.getElementById('left').value || 0;
const top = +document.getElementById('top').value || 0;
const width = +document.getElementById('width').value || 640;
const height = +document.getElementById('height').value || 480;
finclip.setPosition({ width, height, left, top });
};

View File

@ -0,0 +1,17 @@
<html>
<head></head>
<body>
<div>
<button onclick="openFinClipWindow()">open</button>
<button onclick="closeFinClipWindow()">close</button>
</div>
<div>
left<input type="number" id="left" name="left" value="10">
top<input type="number" id="top" name="top" value="10">
width<input type="number" id="width" name="width" value="1000">
height<input type="number" id="height" name="height" value="1000">
<button onclick="setFinClipPosition()">set position</button>
</div>
</body>
<script src="../src/mainScript.js"></script>
</html>

View File

@ -0,0 +1,21 @@
set(CMAKE_C_COMPILER gcc)
project(FinClipGTK C)
# Use the package PkgConfig to detect GTK+ headers/library files
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED gtk+-3.0)
set(FINCLIP_GTK_DEMO "FinClipGTK")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<$<CONFIG:Debug>:>)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<$<CONFIG:Debug>:>)
# Add other flags to the compiler
add_definitions(${GTK_CFLAGS_OTHER})
add_executable(${FINCLIP_GTK_DEMO} main.c)
target_include_directories(${FINCLIP_GTK_DEMO} PRIVATE ${GTK_INCLUDE_DIRS})
target_include_directories(${FINCLIP_GTK_DEMO} PRIVATE FinClipSDKWrapper)
add_dependencies(${FINCLIP_GTK_DEMO} FinClipSDKWrapper)
target_link_libraries(${FINCLIP_GTK_DEMO} FinClipSDKWrapper ${GTK_LIBRARIES})
set(OUTPUT_FILE FinClipGTK)
copy_files("${FINCLIP_GTK_DEMO}" "${OUTPUT_FILE}" "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/core/$<CONFIGURATION>")

191
examples/gtk/main.c 100644
View File

@ -0,0 +1,191 @@
/**
* Demo GTK+ Application that illustrates data entry.
*
* M. Horauer
*/
#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <stddef.h>
#include "../../wrapper/src/public/finclip_wrapper.h"
typedef struct {
GtkWidget *dateDate;
GtkWidget *idNbr;
GtkWidget *emailAddr;
GtkWidget *gnameEntry;
GtkWidget *fnameEntry;
GtkWidget *streetEntry;
GtkWidget *cityEntry;
GtkWidget *zipEntry;
GtkWidget *phoneEntry;
GtkWidget *byearSpin;
GtkWidget *bmonthSpin;
GtkWidget *bdaySpin;
} diaWidgets;
typedef struct {
GtkApplication *app;
GtkWidget *window;
GtkWidget *img;
diaWidgets *d;
} appWidgets;
/***************************************************************** PROTOTYPES */
static void activate(GtkApplication *app, gpointer user_data);
static void cancel_callback(GtkWidget *widget, gpointer user_data);
static void clear_callback(GtkWidget *widget, gpointer user_data);
static void add_callback(GtkWidget *widget, gpointer user_data);
static gint get_next_id(void);
static gint get_next_id(void) { return 12; }
/************************************************************ Cancel Callback */
static void cancel_callback(GtkWidget *widget, gpointer user_data) {}
/************************************************************* Clear Callback */
static void clear_callback(GtkWidget *widget, gpointer user_data) {
finclip_close_all_applet();
}
/*************************************************************** Add Callback */
static void add_callback(GtkWidget *widget, gpointer user_data) {
IPackerFactory *factory = finclip_get_packer_factory();
IFinConfigPacker *packer = finclip_packer_factory_get_config_packer(factory);
IFinConfig *config = finclip_config_packer_new_config(packer);
finclip_config_set_app_store(config, 1);
finclip_config_set_app_key(config,
"22LyZEib0gLTQdU3MUauAQVLIkNNhTSGIN42gXzlAsk=");
finclip_config_set_secret(config, "ae55433be2f62915");
finclip_config_set_domain(config, "https://finchat-mop-b.finogeeks.club");
finclip_config_packer_add_config(packer, config);
finclip_initialize(packer);
finclip_start_applet(NULL, 1, "60e3c059949a5300014d0c07", "", NULL, "", NULL);
}
/********************************************************* nameentry_callback */
static void nameentry_callback(GtkWidget *widget, gpointer user_data) {
gint study_prog_nr = 54;
gchar *org = "uni";
gchar *cnt = "net";
gchar *gname;
gchar *fname;
gchar email[256];
gchar dateStamp[256];
gchar *year;
gchar id[256] = "";
appWidgets *a = (appWidgets *)user_data;
/* construct the eMail address */
gname = (gchar *)gtk_entry_get_text(GTK_ENTRY(a->d->gnameEntry));
fname = (gchar *)gtk_entry_get_text(GTK_ENTRY(a->d->fnameEntry));
/* we update the fields on the top only when we got a family name */
if ((g_strcmp0(gname, "") != 0) && (g_strcmp0(fname, "") != 0)) {
g_sprintf(email, "%s.%s@%s.%s", gname, fname, org, cnt);
gtk_label_set_label(GTK_LABEL(a->d->emailAddr), email);
/* update date info when Family Name was entered */
gtk_label_set_label(GTK_LABEL(a->d->dateDate), dateStamp);
/* construct matrnum when Family Name was entered */
year = g_strndup(dateStamp, 4);
g_snprintf(id, 10, "%s%d%03d", year, study_prog_nr, get_next_id());
gtk_label_set_label(GTK_LABEL(a->d->idNbr), id);
}
}
/***************************************************************** ADD WINDOW */
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *box;
GtkWidget *ebox;
GtkWidget *grid;
GtkWidget *date_label;
GtkWidget *id_label;
GtkWidget *email_label;
GtkWidget *gname_label;
GtkWidget *fname_label;
GtkWidget *street_label;
GtkWidget *city_label;
GtkWidget *zip_label;
GtkWidget *phone_label;
GtkWidget *birth_label;
GtkWidget *c_button;
GtkWidget *l_button;
GtkWidget *a_button;
appWidgets *a = (appWidgets *)user_data;
/* create a window with title, default size,and icons */
a->window = gtk_application_window_new(a->app);
gtk_window_set_application(GTK_WINDOW(a->window), GTK_APPLICATION(a->app));
gtk_window_set_title(GTK_WINDOW(a->window), "Student Management Toolbox");
gtk_window_set_default_size(GTK_WINDOW(a->window), 400, 300);
gtk_window_set_resizable(GTK_WINDOW(a->window), FALSE);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
gtk_container_add(GTK_CONTAINER(a->window), GTK_WIDGET(box));
gtk_container_set_border_width(GTK_CONTAINER(a->window), 10);
/* grid: image and labels */
grid = gtk_grid_new();
gtk_grid_set_column_spacing(GTK_GRID(grid), 5);
gtk_grid_set_row_spacing(GTK_GRID(grid), 5);
gtk_widget_set_size_request(GTK_WIDGET(grid), 400, 90);
gtk_widget_set_valign(GTK_WIDGET(grid), GTK_ALIGN_CENTER);
gtk_widget_set_halign(GTK_WIDGET(grid), GTK_ALIGN_CENTER);
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(grid), TRUE, TRUE, 0);
gname_label = gtk_widget_new(GTK_TYPE_LABEL, "label", "Appid", "xalign", 1.0,
"yalign", 0.5, NULL);
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(gname_label), 0, 3, 1, 1);
a->d->gnameEntry = gtk_entry_new();
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(a->d->gnameEntry), 1, 3, 1, 1);
street_label = gtk_widget_new(GTK_TYPE_LABEL, "label", "secret:", "xalign",
1.0, "yalign", 0.5, NULL);
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(street_label), 0, 4, 1, 1);
a->d->streetEntry = gtk_entry_new();
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(a->d->streetEntry), 1, 4, 1, 1);
zip_label = gtk_widget_new(GTK_TYPE_LABEL, "label", "key:", "xalign", 1.0,
"yalign", 0.5, NULL);
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(zip_label), 0, 5, 1, 1);
a->d->zipEntry = gtk_entry_new();
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(a->d->zipEntry), 1, 5, 1, 1);
phone_label = gtk_widget_new(GTK_TYPE_LABEL, "label", "domain:", "xalign",
1.0, "yalign", 0.5, NULL);
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(phone_label), 2, 5, 1, 1);
a->d->phoneEntry = gtk_entry_new();
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(a->d->phoneEntry), 3, 5, 1, 1);
/* lowerbox: buttons */
c_button = gtk_button_new_with_mnemonic("_Cancel");
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(c_button), 1, 7, 1, 1);
g_signal_connect(G_OBJECT(c_button), "clicked", G_CALLBACK(cancel_callback),
(gpointer)a);
l_button = gtk_button_new_with_mnemonic("C_lear");
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(l_button), 2, 7, 1, 1);
g_signal_connect(G_OBJECT(l_button), "clicked", G_CALLBACK(clear_callback),
(gpointer)a);
a_button = gtk_button_new_with_mnemonic("_Add");
gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(a_button), 3, 7, 1, 1);
g_signal_connect(G_OBJECT(a_button), "clicked", G_CALLBACK(add_callback),
(gpointer)a);
gtk_widget_show_all(GTK_WIDGET(a->window));
}
/*********************************************************************** main */
int main(int argc, char **argv) {
int status;
appWidgets *a = g_malloc(sizeof(appWidgets));
a->d = g_malloc(sizeof(diaWidgets));
a->app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(G_OBJECT(a->app), "activate", G_CALLBACK(activate),
(gpointer)a);
status = g_application_run(G_APPLICATION(a->app), argc, argv);
g_object_unref(a->app);
g_free(a->d);
g_free(a);
return status;
}
/** EOF */

View File

@ -0,0 +1,6 @@
# 下载base包
# 下载python包
# demo接受

View File

@ -0,0 +1,105 @@
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout)
import finclip
import sys
import json
class PythonCallback(finclip.Callback):
# Define Python class 'constructor'
def __init__(self):
# Call C++ base class constructor
finclip.Callback.__init__(self)
def Run(self, event, param):
print(event)
print(param)
return "{}"
appid = "60e3c059949a5300014d0c07"
callback = PythonCallback().__disown__()
def start_finclip():
factory = finclip.finclip_get_packer_factory()
packer = finclip.finclip_packer_factory_get_config_packer(factory)
config = finclip.finclip_config_packer_new_config(packer)
finclip.finclip_config_set_app_store(config, 1)
finclip.finclip_config_set_app_key(config,
"22LyZEib0gLTQdU3MUauAQVLIkNNhTSGIN42gXzlAsk=")
finclip.finclip_config_set_secret(config, "ae55433be2f62915")
finclip.finclip_config_set_domain(
config, "https://finchat-mop-b.finogeeks.club")
if sys.platform == 'win32':
finclip.finclip_config_set_value(
config, finclip.FINCLIP_CONFIG_EXE_PATH, "C:/project/finclipsdk-desktop/build/core/Debug/finclip.exe")
finclip.finclip_config_packer_add_config(packer, config)
# callback.thisown = 0
finclip.finclip_register_callback_cpp(
packer, finclip.kApplet, "test", callback)
finclip.finclip_register_callback_cpp(
packer, finclip.kWebView, "test_webapi", PythonCallback().__disown__())
finclip.finclip_initialize(packer)
finclip.finclip_start_applet(1, appid)
print("---------------------------------" + str(callback.thisown))
x = {
"name": "John",
"age": 30,
"city": "New York"
}
def send_webapi():
print(123)
finclip.finclip_invoke_api_cpp(
finclip.kWebView, appid, "test", json.dumps(x), PythonCallback().__disown__())
class Dialog(QDialog):
NumGridRows = 3
NumButtons = 4
def __init__(self):
super(Dialog, self).__init__()
self.createFormGroupBox()
buttonBox = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.formGroupBox)
# mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle("Form Layout - pythonspot.com")
def createFormGroupBox(self):
startBtn = QPushButton(self)
startBtn.setText("start finclip")
startBtn.clicked.connect(start_finclip)
webapiBtn = QPushButton(self)
webapiBtn.setText("invoke webapi")
webapiBtn.clicked.connect(send_webapi)
self.formGroupBox = QGroupBox("Form layout")
layout = QFormLayout()
layout.addRow(QLabel("Name:"), QLineEdit())
layout.addRow(QLabel("Country:"), QComboBox())
layout.addRow(QLabel("Age:"), QSpinBox())
layout.addWidget(startBtn)
layout.addWidget(webapiBtn)
self.formGroupBox.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Dialog()
sys.exit(dialog.exec_())

View File

View File

@ -0,0 +1,65 @@
## 📦 安装第三方依赖
Windows 小程序运行环境需要安装以下依赖,请提前配置环境:
- 请下载依赖包[点我下载](https://public-1251849568.cos.ap-guangzhou.myqcloud.com/sdk/lib.zip)
- 下载完后解压到vendor/finclip目录中
- 建议使用 Visual Studio 2019 版本 [点我下载](https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0)
**注意:依赖包必须随缩主程序一同发布,并在独立目录中存放。**
解压后文件目录结构如下:
```
vendor
|--finclip
| |--lib
| |--****
| |--****
| |--****
...
```
### 第一步 引入头文件
```c++
#include "finclip_wrapper.h" //引入头文件
#pragma comment(lib, "FinClipSDKWrapper.lib") //引入链接库
```
### 第二步 初始化SDK
```c++
FinConfig config = {
1,
"https://api.finclip.com",
"/api/v1/mop",
"这里输入SDK KEY",
"这里输入SDK SECRET",
"",
1
};
IFinConfigPacker* configpacker = NewFinConfigPacker();
configpacker->AddConfig(config);
Initialize(hInstance, configpacker);
```
- **SDK KEY****SDK SECRET** 可以从 [FinClip](https://finclip.com/#/home) 获取,点 [这里](https://finclip.com/#/register) 注册账号;
- 进入平台后,在「应用管理」页面添加你自己的包名后,点击「复制」即可获得 key\secret\apisever 字段;
- **apiServer****apiPrefix** 是固定字段,请直接参考本 DEMO
- **小程序 ID** 是管理后台上架的小程序 APP ID需要在「小程序管理」中创建并在「应用管理」中关联
> 小程序 ID 与 微信小程序ID 不一样哦!(这里是特指 FinClip 平台的 ID
### 第三步 打开小程序
```c++
int server_type = 1;
init_finclipsdk(server_type,wappkey, wsecret);
IFinPacker* packer = NewFinPacker();
packer->BeginPacker();
packer->AddField("appId");
packer->AddValue("appId");
packer->EndPacker();
StartApplet(server_type, utf8_encode(wappid).c_str(), packer, finclip_applet_callback);
packer->Release();
```

View File

@ -0,0 +1,466 @@
// FinClip.cpp : Defines the entry point for the application.
//
#include "../../src/finclip_api.h"
#include "resource.h"
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <winuser.h>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
#include "json.hpp"
#pragma comment(lib, "../../vendor/win/x64/FinClipSDKWrapper.lib")
#define MAX_LOADSTRING 100
using namespace std;
HINSTANCE hInst;
HWND gHwnd; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM MyRegisterClass1(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND hWnd_appkey;
HWND hWnd_secret;
HWND hWnd_appid;
HWND hWnd_domain;
HWND hWnd_type;
HWND hWnd_container;
HWND hWnd_applet;
BOOL is_initialized = FALSE;
std::string offline_base_path;
std::string offline_applet_path;
std::string Utf8Encode(const std::wstring& wstr, int cp = CP_UTF8) {
if (wstr.empty()) return std::string();
int size_needed =
WideCharToMultiByte(cp, 0, &wstr[0], static_cast<int>(wstr.size()),
nullptr, 0, nullptr, nullptr);
std::string str(size_needed, 0);
WideCharToMultiByte(cp, 0, &wstr[0], static_cast<int>(wstr.size()), &str[0],
size_needed, nullptr, nullptr);
return str;
}
// Convert an UTF8 string to a wide Unicode String
std::wstring Utf8Decode(const std::string& str, int cp = CP_UTF8) {
if (str.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(
cp, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
std::wstring wstr(size_needed, 0);
MultiByteToWideChar(cp, 0, &str[0], static_cast<int>(str.size()), &wstr[0],
size_needed);
return wstr;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine,
_In_ int nCmdShow) {
SetProcessDPIAware();
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_FINCLIPWIN32DEMO, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
MyRegisterClass1(hInstance);
if (InitInstance(hInstance, nCmdShow) == 0) {
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, nullptr);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return static_cast<int>(msg.wParam);
}
ATOM MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, nullptr);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, nullptr);
return RegisterClassExW(&wcex);
}
ATOM MyRegisterClass1(HINSTANCE hInstance) {
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, nullptr);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"child_finclip";
wcex.hIconSm = LoadIcon(wcex.hInstance, nullptr);
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
hInst = hInstance; // Store instance handle in our global variable
HWND hwnd =
CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
0, 1000, 1200, nullptr, nullptr, hInstance, nullptr);
HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = {sizeof(mi)};
if (!GetMonitorInfo(hmon, &mi)) return FALSE;
if (hwnd == nullptr) {
return FALSE;
}
int width = 450;
int height = 1000;
SetWindowPos(hwnd, nullptr, mi.rcMonitor.left, mi.rcMonitor.top, width,
height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
gHwnd = hwnd;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
void CustomApi(const char* event, const char* param,
FinclipApiCallback callback) {
std::string data = param;
std::string e = event;
std::string res = R"({"data":"ok"})";
callback(res.c_str());
}
void InitFinclipsdk(int app_store, const std::wstring& wappkey,
const std::wstring& wsecret, const std::wstring& wdomain) {
if (is_initialized != 0) {
return;
}
std::string appkey = Utf8Encode(wappkey);
std::string secret = Utf8Encode(wsecret);
std::string domain = Utf8Encode(wdomain);
auto* factory = finclip_get_packer_factory();
auto* packer = finclip_packer_factory_get_config_packer(factory);
auto* config = finclip_config_packer_new_config(packer);
finclip_config_packer_add_config(packer, config);
finclip_config_set_app_store(config, app_store);
finclip_config_set_app_key(config, appkey.c_str());
finclip_config_set_secret(config, secret.c_str());
finclip_config_set_domain(config, domain.c_str());
finclip_config_set_start_flag(config, kAppletSync);
finclip_config_set_show_loading(config, false);
finclip_register_callback(packer, kApplet, "api", CustomApi);
finclip_register_callback(packer, kWebView, "webapi", CustomApi);
finclip_initialize(packer);
is_initialized = TRUE;
}
// void FinclipAppletCallback(IEvent* event) {
// std::string buffer = event->GetBuffer();
// if (event->IsEmpty() == 0) {
// const char* val = event->GetStr("hWnd");
// std::string s(val);
// hWnd_applet = (HWND)strtoul(s.c_str(), nullptr, 16);
// }
// event->Release();
// }
// window procedure
// 定义窗口的行为
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
switch (message) {
case WM_COMMAND:
if (LOWORD(wParam) == IDM_SENDMESSAGE) {
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
std::wstring wappid(appid);
// CleanCache();
break;
}
// 打开隐藏小程序进程的例子
if (LOWORD(wParam) == IDM_SENDMESSAGE_1) {
// 小程序启动过一次, 调用unbind后, 再次打开
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
std::wstring wappid(appid);
// 重新显示小程序
// StartApplet(hWnd_container, 0, Utf8Encode(wappid).c_str(), "",
// nullptr,
// "", nullptr);
// 宿主处理自己的窗口
ShowWindow(hWnd_container, SW_SHOWNORMAL);
break;
}
if (LOWORD(wParam) == IDM_SENDMESSAGE_2) {
// 关闭但不销毁(隐藏)小程序进程,
// CloseApplet(hWnd_container, false);
// 宿主处理自己的窗口
ShowWindow(hWnd_container, SW_HIDE);
break;
}
// open按钮处理逻辑
if (LOWORD(wParam) == IDM_START_APPLET) {
WCHAR key[1024];
GetWindowText(hWnd_appkey, key, 1023);
WCHAR secret[1024];
GetWindowText(hWnd_secret, secret, 1023);
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
WCHAR domain[1024];
GetWindowText(hWnd_domain, domain, 1023);
WCHAR type[1024];
GetWindowText(hWnd_type, type, 1023);
std::wstring wappkey(key);
std::wstring wsecret(secret);
std::wstring wappid(appid);
std::wstring wdomain(domain);
std::wstring wtype(type);
int appstore = 1;
if (wappkey.length() == 0) {
MessageBox(nullptr, L"无效的appKey", L"错误", 0);
return 0;
}
if (wsecret.length() == 0) {
MessageBox(nullptr, L"无效的Secret", L"错误", 0);
return 0;
}
if (wappid.length() == 0) {
MessageBox(nullptr, L"无效的appid", L"错误", 0);
return 0;
}
if (wdomain.length() == 0) {
MessageBox(nullptr, L"无效的domain", L"错误", 0);
return 0;
}
if (wtype.length() == 0) {
MessageBox(nullptr, L"无效的type", L"错误", 0);
return 0;
}
InitFinclipsdk(appstore, wappkey, wsecret, wdomain);
// IPackerFactory* factory = GetPackerFactory();
// IFinConfigPacker* configpacker = factory->GetFinConfigPacker();
// IFinConfig* config = configpacker->GetConfig(appstore);
// config->SetAppWindowStyle(std::stol(wtype));
// IFinPacker* packer = factory->GetFinPacker();
// packer->BeginPacker();
// packer->Add("appId", Utf8Encode(wappid).c_str());
// packer->Add("query", "1");
// packer->EndPacker();
// int len = packer->GetBufferSize() + 1;
// auto* ret = new unsigned char[len];
// memset(ret, 0, len);
// packer->Dump(ret, &len);
// delete[] ret;
if (wtype == L"1") {
// 嵌入模式, 准备一个窗口, 用于嵌入小程序
if (hWnd_container == nullptr) {
hWnd_container =
CreateWindowW(L"child_finclip", L"child_finclip",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 1024, 768,
nullptr, nullptr, hInst, nullptr);
}
finclip_start_applet(appstore, Utf8Encode(wappid).c_str());
} else {
finclip_start_applet(appstore, Utf8Encode(wappid).c_str());
}
// packer->Release();
}
break;
case WM_SIZE: {
if (hWnd_container == hWnd) {
// 嵌入模式须重新设置窗口大小
WCHAR type[1024];
GetWindowText(hWnd_type, type, 1023);
std::wstring wtype(type);
if (wtype == L"1") {
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
RECT rect;
GetClientRect(hWnd_container, &rect);
// SetAppletPos(Utf8Encode(std::wstring(appid)).c_str(), 0, 0,
// rect.right - rect.left, rect.bottom - rect.top, true);
}
}
break;
}
case WM_DESTROY: {
if (hWnd == hWnd_container) {
// 收到WM_DESTROY消息, 表示容器窗口被销毁, 需要SDK的资源
// CloseApplet(hWnd, true);
hWnd_container = nullptr;
return 0;
}
if (hWnd == gHwnd) {
// 只有主窗口关闭时退出进程
PostQuitMessage(0);
}
break;
}
case WM_CREATE: {
if (hWnd_appkey != nullptr)
return DefWindowProcW(hWnd, message, wParam, lParam);
CreateWindowW(L"static", L"AppKEY", WS_CHILD | WS_VISIBLE, 20, 20, 60, 30,
hWnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance,
nullptr);
CreateWindowW(L"static", L"Secret", WS_CHILD | WS_VISIBLE, 20, 60, 60, 30,
hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance,
nullptr);
CreateWindowW(L"static", L"appid", WS_CHILD | WS_VISIBLE, 20, 100, 60, 30,
hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance,
nullptr);
CreateWindowW(L"static", L"domain", WS_CHILD | WS_VISIBLE, 20, 140, 60,
30, hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance,
nullptr);
CreateWindowW(L"static", L"window_type", WS_CHILD | WS_VISIBLE, 20, 180,
60, 30, hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance,
nullptr);
HMONITOR hmon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = {sizeof(mi)};
if (!GetMonitorInfo(hmon, &mi)) return 0;
wstring domain(L"https://finchat-mop-b.finogeeks.club:443");
wstring appkey(L"22LyZEib0gLTQdU3MUauAQVLIkNNhTSGIN42gXzlAsk=");
wstring appid(L"60e3c059949a5300014d0c07");
wstring secret(L"ae55433be2f62915");
auto path = std::filesystem::current_path();
if (std::filesystem::exists("config.json")) {
std::ifstream t("config.json");
std::stringstream buffer;
buffer << t.rdbuf();
auto obj = nlohmann::json::parse(buffer.str());
auto field = obj.find("domain");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
domain = wstring(s.begin(), s.end());
}
field = obj.find("appkey");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
appkey = wstring(s.begin(), s.end());
}
field = obj.find("appid");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
appid = wstring(s.begin(), s.end());
}
field = obj.find("secret");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
secret = wstring(s.begin(), s.end());
}
field = obj.find("offline_applet_path");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
offline_applet_path = string(s.begin(), s.end());
}
field = obj.find("offline_base_path");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
offline_base_path = string(s.begin(), s.end());
}
}
hWnd_appkey = CreateWindowW(
L"EDIT", appkey.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 20, 300, 30, hWnd, (HMENU)IDM_APPLET_APPKEY,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
hWnd_secret = CreateWindowW(
L"EDIT", secret.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 60, 300, 30, hWnd, (HMENU)IDM_APPLET_SECRET,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
// 5ea0401463cb900001d73865 wxdemo
// 5ea0412663cb900001d73867 webview
// 5ea6d3bad262a7000141280d quote
hWnd_appid = CreateWindowW(
L"EDIT", appid.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 100, 300, 30, hWnd, (HMENU)IDM_APPLET_APPID,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
hWnd_domain = CreateWindowW(
L"EDIT", domain.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 140, 300, 30, hWnd, (HMENU)IDM_APPLET_DOMAIN,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
hWnd_type = CreateWindowW(
L"EDIT", L"0", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT, 100, 180,
300, 30, hWnd, (HMENU)IDM_APPLET_DOMAIN,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
int button_y = 240;
CreateWindowW(L"BUTTON", L"open", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
100, button_y, 200, 50, hWnd, (HMENU)IDM_START_APPLET,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
button_y += 60;
CreateWindowW(L"BUTTON", L"cleancache",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, button_y, 200,
50, hWnd, (HMENU)IDM_SENDMESSAGE,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
button_y += 60;
CreateWindowW(L"BUTTON", L"bind_applet",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, button_y, 200,
50, hWnd, (HMENU)IDM_SENDMESSAGE_1,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
button_y += 60;
CreateWindowW(L"BUTTON", L"unbind_applet",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, button_y, 200,
50, hWnd, (HMENU)IDM_SENDMESSAGE_2,
((LPCREATESTRUCT)lParam)->hInstance, nullptr);
} break;
}
return DefWindowProcW(hWnd, message, wParam, lParam);
}

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -111,7 +111,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)vendor\finclip\lib\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)\..\..\vendor\win\x86\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -131,7 +131,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)vendor\finclip\lib\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)\..\..\vendor\win\x86\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -147,7 +147,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)vendor\finclip\lib\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)\..\..\vendor\win\x64\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -167,7 +167,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)vendor\finclip\lib\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
<Command>xcopy /Y/E/H/C/I $(SolutionDir)\..\..\vendor\win\x64\* $(SolutionDir)build\bin\$(Platform)\$(Configuration)\ </Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -0,0 +1,36 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by finclip-win32-demo.rc
//
#define IDC_MYICON 2
#define IDD_FINCLIPWIN32DEMO_DIALOG 102
#define IDS_APP_TITLE 103
#define IDD_ABOUTBOX 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_FINCLIPWIN32DEMO 107
#define IDI_SMALL 108
#define IDC_FINCLIPWIN32DEMO 109
#define IDR_MAINFRAME 128
#define ID_FILE_IDM 32771
#define IDM_SENDMESSAGE 32772
#define ID_FILE_IDM32773 32773
#define IDM_START_APPLET 32774
#define IDM_APPLET_APPKEY 32775
#define IDM_APPLET_SECRET 32776
#define IDM_APPLET_APPID 32777
#define IDM_APPLET_DOMAIN 32778
#define IDC_STATIC -1
#define IDM_SENDMESSAGE_1 32784
#define IDM_SENDMESSAGE_2 32785
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 129
#define _APS_NEXT_COMMAND_VALUE 32779
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,524 +0,0 @@
// FinClip.cpp : Defines the entry point for the application.
//
#include "Resource.h"
#include "vendor/finclip/include/finclip_wrapper.h"
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <malloc.h>
#include <memory.h>
#include <stdlib.h>
#include <tchar.h>
#include "json.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
#pragma comment(lib, "FinClipSDKWrapper.lib")
#define MAX_LOADSTRING 100
using namespace std;
using json = nlohmann::json;
using namespace com::finogeeks::finclip::wrapper;
HINSTANCE hInst;
HWND gHwnd; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM MyRegisterClass1(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND hWnd_appkey;
HWND hWnd_secret;
HWND hWnd_appid;
HWND hWnd_domain;
HWND hWnd_type;
HWND hWnd_container;
HWND hWnd_applet;
BOOL is_initialized = FALSE;
RECT g_rect_;
std::string offline_base_path;
std::string offline_applet_path;
std::string utf8_encode(const std::wstring &wstr, int CP = CP_UTF8) {
if (wstr.empty())
return std::string();
int size_needed = WideCharToMultiByte(CP, 0, &wstr[0], (int)wstr.size(), NULL,
0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed,
NULL, NULL);
return strTo;
}
// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str, int CP = CP_UTF8) {
if (str.empty())
return std::wstring();
int size_needed =
MultiByteToWideChar(CP, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
class CustomWebApi : public IApi {
void invoke(const char *event, const char *param, IApiCallback *callback) {
std::string data = param;
std::string e = event;
callback->Callback("{\"data\":\"ok\"}");
}
FinClipApiType GetApiType() const { return FinClipApiType::kWebView; }
const char *apis() { return "customWebApi"; }
size_t size() { return 1l; }
};
class CustomApi : public IApi {
void invoke(const char *event, const char *param, IApiCallback *callback) {
std::string data = param;
std::string e = event;
callback->Callback("{\"data\":\"ok\"}");
}
FinClipApiType GetApiType() const { return FinClipApiType::kApplet; }
const char *apis() { return "customApi"; }
size_t size() { return 1l; }
};
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine,
_In_ int nCmdShow) {
SetProcessDPIAware();
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_FINCLIPWIN32DEMO, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
MyRegisterClass1(hInstance);
if (!InitInstance(hInstance, nCmdShow)) {
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, NULL);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, NULL);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, NULL);
return RegisterClassExW(&wcex);
}
ATOM MyRegisterClass1(HINSTANCE hInstance) {
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, NULL);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"child_finclip";
wcex.hIconSm = LoadIcon(wcex.hInstance, NULL);
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
hInst = hInstance; // Store instance handle in our global variable
DWORD dwStyle =
WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX; //<2F><><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD><EFBFBD>ʽ
HWND hWnd =
CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
0, 1000, 800, nullptr, nullptr, hInstance, nullptr);
HMONITOR hmon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = {sizeof(mi)};
if (!GetMonitorInfo(hmon, &mi))
return FALSE;
if (!hWnd) {
return FALSE;
}
int width = 450;
int height = 500;
SetWindowPos(hWnd, NULL, mi.rcMonitor.left, mi.rcMonitor.top, width, height,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
gHwnd = hWnd;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
void init_finclipsdk(int app_store, std::wstring wappkey, std::wstring wsecret,
std::wstring wdomain) {
if (is_initialized != 0) {
return;
}
std::string appkey = utf8_encode(wappkey);
std::string secret = utf8_encode(wsecret);
std::string domain = utf8_encode(wdomain);
IPackerFactory *factory = GetPackerFactory();
IFinConfigPacker *configpacker = factory->GetFinConfigPacker();
IFinConfig *config = configpacker->NewConfig();
config->SetAppStore(app_store);
config->SetApiPrefix("/api/v1/mop");
config->SetAppKey(appkey.c_str());
config->SetSecret(secret.c_str());
config->SetDomain(domain.c_str());
config->SetEncryptType(1);
config->SetFinger("");
config->SetAppWindowStyle(1);
config->SetOfflineApplet(offline_applet_path.data());
config->SetOfflineBaseLibrary(offline_base_path.data());
config->SetStartFlag(StartFlags::kAppletSync);
config->SetShowLoading(0);
configpacker->AddConfig(config);
auto *c_api = new CustomApi();
configpacker->RegisterApi(c_api);
auto *c_web_api = new CustomWebApi();
configpacker->RegisterApi(c_web_api);
Initialize(hInst, configpacker);
is_initialized = TRUE;
}
void finclip_applet_callback(IEvent *event) {
std::string buffer = event->GetBuffer();
int i = 0;
if (!event->IsEmpty()) {
const char *val = event->GetStr("hWnd");
std::string s(val);
hWnd_applet = (HWND)strtoul(s.c_str(), NULL, 16);
}
event->Release();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
HWND hwndButtonCintinue;
switch (message) {
case WM_COMMAND:
if (LOWORD(wParam) == IDM_SENDMESSAGE) {
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
std::wstring wappid(appid);
CleanCache();
// if (hWnd_container) {
// DestroyWindow(hWnd_container);
// }
// InvokeWebApi(utf8_encode(wappid).c_str(), "test_custom_api",
// "{params:'a'}");
break;
}
if (LOWORD(wParam) == IDM_START_APPLET) {
WCHAR key[1024];
GetWindowText(hWnd_appkey, key, 1023);
WCHAR secret[1024];
GetWindowText(hWnd_secret, secret, 1023);
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
WCHAR domain[1024];
GetWindowText(hWnd_domain, domain, 1023);
WCHAR type[1024];
GetWindowText(hWnd_type, type, 1023);
std::wstring wappkey(key);
std::wstring wsecret(secret);
std::wstring wappid(appid);
std::wstring wdomain(domain);
std::wstring wtype(type);
if (wappkey.length() == 0) {
MessageBox(NULL, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>appKey", L"<EFBFBD><EFBFBD>ʾ", 0);
return 0;
}
if (wsecret.length() == 0) {
MessageBox(NULL, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Secret", L"<EFBFBD><EFBFBD>ʾ", 0);
return 0;
}
if (wappid.length() == 0) {
MessageBox(NULL, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>appid", L"<EFBFBD><EFBFBD>ʾ", 0);
return 0;
}
if (wdomain.length() == 0) {
MessageBox(NULL, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>domain", L"<EFBFBD><EFBFBD>ʾ", 0);
return 0;
}
if (wtype.length() == 0) {
MessageBox(NULL, L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>type", L"<EFBFBD><EFBFBD>ʾ", 0);
return 0;
}
int appstore = 1;
IPackerFactory *factory = GetPackerFactory();
IFinConfigPacker *configpacker = factory->GetFinConfigPacker();
IFinConfig *config = configpacker->GetConfig(appstore);
config->SetAppWindowStyle(std::stol(wtype));
IFinPacker *packer = factory->GetFinPacker();
packer->BeginPacker();
packer->Add("appId", utf8_encode(wappid).c_str());
packer->Add("query", "1");
packer->EndPacker();
int len = packer->GetBufferSize() + 1;
auto *ret = new unsigned char[len];
memset(ret, 0, len);
packer->Dump(ret, &len);
delete[] ret;
if (hWnd_container == nullptr) {
// hWnd_container = CreateWindowW(L"child_finclip", L"<22><><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD>",
// WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0,
// 0, 1920, 1080, NULL, NULL,
// hInst, NULL);
hWnd_container = CreateWindowW(L"child_finclip", L"<EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD>",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0,
1024, 768, NULL, NULL, hInst, NULL);
}
HRESULT hr =
StartApplet(hWnd_container, appstore, utf8_encode(wappid).c_str(), "",
packer, "", finclip_applet_callback);
if (hr == S_OK) {
}
// SetWindowPos(h, NULL, 0, 300, 400, 436, 0);
packer->Release();
}
break;
case WM_CLOSE: {
if (hWnd == hWnd_container) {
hWnd_container = NULL;
}
break;
}
case WM_SHOWWINDOW: {
if (hWnd == hWnd_container) {
/*RECT rc;
GetWindowRect(hWnd, &rc);
auto left = 0;
auto top = 0;
auto width = rc.right - rc.left;
auto height = rc.bottom - rc.top;
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
SetAppletPos(utf8_encode(std::wstring(appid)).c_str(), 1, 0, top, width,
height);
*/
} else {
WCHAR key[1024];
GetWindowText(hWnd_appkey, key, 1023);
WCHAR secret[1024];
GetWindowText(hWnd_secret, secret, 1023);
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
WCHAR domain[1024];
GetWindowText(hWnd_domain, domain, 1023);
std::wstring wappkey(key);
std::wstring wsecret(secret);
std::wstring wappid(appid);
std::wstring wdomain(domain);
init_finclipsdk(1, wappkey, wsecret, wdomain);
}
} break;
case WM_SIZE: {
WCHAR type[1024];
GetWindowText(hWnd_type, type, 1023);
std::wstring wtype(type);
if (wtype == L"1") {
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
WCHAR appid[1024];
GetWindowText(hWnd_appid, appid, 1023);
RECT rect;
GetClientRect(hWnd_container, &rect);
SetAppletPos(utf8_encode(std::wstring(appid)).c_str(), 0, 0,
rect.right - rect.left, rect.bottom - rect.top, true);
}
break;
}
// case WM_PAINT:
// {
// // WCHAR type[1024];
// // GetWindowText(hWnd_type, type, 1023);
// // std::wstring wtype(type);
// // if (wtype == L"1") {
// // RECT rect;
// // GetClientRect(hWnd_container, &rect);
// // WCHAR appid[1024];
// // GetWindowText(hWnd_appid, appid, 1023);
// // SetAppletPos(
// // utf8_encode(std::wstring(appid)).c_str(), 0, 0, rect.right -
// rect.left, rect.bottom - rect.top,
// // true);
// // }
// break;
// }
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
case WM_CREATE: {
if (hWnd_appkey)
return DefWindowProcW(hWnd, message, wParam, lParam);
CreateWindowW(L"static", L"AppKEY", WS_CHILD | WS_VISIBLE, 20, 20, 60, 30,
hWnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"static", L"Secret", WS_CHILD | WS_VISIBLE, 20, 60, 60, 30,
hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"static", L"appid", WS_CHILD | WS_VISIBLE, 20, 100, 60, 30,
hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"static", L"domain", WS_CHILD | WS_VISIBLE, 20, 140, 60, 30,
hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"static", L"window_type", WS_CHILD | WS_VISIBLE, 20, 180, 60,
30, hWnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance,
NULL);
HMONITOR hmon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = {sizeof(mi)};
if (!GetMonitorInfo(hmon, &mi))
return false;
auto left = mi.rcMonitor.left;
auto top = mi.rcMonitor.top;
auto width = mi.rcMonitor.right - mi.rcMonitor.left;
auto height = mi.rcMonitor.bottom - mi.rcMonitor.top;
// hWnd_container = CreateWindowW(L"static", L"", WS_CHILD | WS_VISIBLE,
// left,
// top, width, height, hWnd, (HMENU)2,
// ((LPCREATESTRUCT)lParam)->hInstance, NULL);
wstring domain(L"https://finchat-mop-b.finogeeks.club");
wstring appkey(L"22LyZEib0gLTQdU3MUauAQVLIkNNhTSGIN42gXzlAsk=");
wstring appid(L"60e3c059949a5300014d0c07");
wstring secret(L"ae55433be2f62915");
// <20><>exe<78><65><EFBFBD><EFBFBD>, config.json<6F><6E><EFBFBD><EFBFBD>exeͬһĿ¼
// <20><>vs<76><73><EFBFBD><EFBFBD>, config.json<6F><6E><EFBFBD><EFBFBD>Finclip/
auto path = std::filesystem::current_path();
if (std::filesystem::exists("config.json")) {
std::ifstream t("config.json");
std::stringstream buffer;
buffer << t.rdbuf();
auto obj = json::parse(buffer.str());
auto field = obj.find("domain");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
domain = wstring(s.begin(), s.end());
}
field = obj.find("appkey");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
appkey = wstring(s.begin(), s.end());
}
field = obj.find("appid");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
appid = wstring(s.begin(), s.end());
}
field = obj.find("secret");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
secret = wstring(s.begin(), s.end());
}
field = obj.find("offline_applet_path");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
offline_applet_path = string(s.begin(), s.end());
}
field = obj.find("offline_base_path");
if (field != obj.end() && field.value().is_string()) {
auto s = field.value().get<std::string>();
offline_base_path = string(s.begin(), s.end());
}
}
hWnd_appkey = CreateWindowW(
L"EDIT", appkey.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 20, 300, 30, hWnd, (HMENU)IDM_APPLET_APPKEY,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
hWnd_secret = CreateWindowW(
L"EDIT", secret.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 60, 300, 30, hWnd, (HMENU)IDM_APPLET_SECRET,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
// 5ea0401463cb900001d73865 wxdemo
// 5ea0412663cb900001d73867 webview
// 5ea6d3bad262a7000141280d quote
hWnd_appid = CreateWindowW(L"EDIT", appid.c_str(),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT, 100,
100, 300, 30, hWnd, (HMENU)IDM_APPLET_APPID,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
hWnd_domain = CreateWindowW(
L"EDIT", domain.c_str(), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT,
100, 140, 300, 30, hWnd, (HMENU)IDM_APPLET_DOMAIN,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
hWnd_type = CreateWindowW(L"EDIT", L"0",
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT, 100,
180, 300, 30, hWnd, (HMENU)IDM_APPLET_DOMAIN,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
HWND hwndButton =
CreateWindowW(L"BUTTON", L"open", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
100, 250, 200, 50, hWnd, (HMENU)IDM_START_APPLET,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
CreateWindowW(L"BUTTON", L"InvokeWebApi",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 100, 350, 200, 50,
hWnd, (HMENU)IDM_SENDMESSAGE,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
} break;
}
return DefWindowProcW(hWnd, message, wParam, lParam);
}

174
src/finclip_api.h 100644
View File

@ -0,0 +1,174 @@
#ifndef WRAPPER_SRC_PUBLIC_FINCLIP_API_H_
#define WRAPPER_SRC_PUBLIC_FINCLIP_API_H_
#include "finclip_api_const.h"
#ifdef __cplusplus
#include <cstddef>
#else
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct IKnown IKnown;
typedef struct IResultSet IResultSet;
typedef struct IEvent IEvent;
typedef struct IFinPacker IFinPacker;
typedef struct IFinConfig IFinConfig;
typedef struct IFinConfigPacker IFinConfigPacker;
typedef struct IPackerFactory IPackerFactory;
typedef struct Callback Callback;
typedef void (*FinClipSDKCallback)(IEvent*);
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE
finclip_initialize(IFinConfigPacker* configpacker);
/**
* @brief
*/
DLL_EXPORT IPackerFactory* FINSTDMETHODCALLTYPE finclip_get_packer_factory();
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE finclip_start_applet(int appstore,
const char* appid);
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE finclip_close_all_applet();
/**
* @brief appid
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE finclip_close_applet(const char* appid);
/**
* @brief
*
*
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE finclip_set_position(const char* appid,
int left, int top,
int width,
int height);
/**
* @brief
*/
DLL_EXPORT IFinConfigPacker* FINSTDMETHODCALLTYPE
finclip_packer_factory_get_config_packer(IPackerFactory* factory);
/**
* @brief
*/
DLL_EXPORT IFinConfig* FINSTDMETHODCALLTYPE
finclip_config_packer_new_config(IFinConfigPacker* packer);
/**
* @brief
*/
DLL_EXPORT IFinConfig* FINSTDMETHODCALLTYPE
finclip_config_packer_get_config(IFinConfigPacker* packer, int appstore);
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE
finclip_config_packer_add_config(IFinConfigPacker* packer, IFinConfig* config);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_register_callback(IFinConfigPacker* packer, FinClipApiType type,
const char* apis, FinclipApiHandle handle);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_app_store(IFinConfig* config, int app_store);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_app_key(IFinConfig* config, const char* app_key);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_secret(IFinConfig* config, const char* secret);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_domain(IFinConfig* config, const char* domain);
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_app_window_style(IFinConfig* config, int type);
/**
* @brief , : StartFlags
* : kBaseLibrarySync | kAppletSync
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_start_flag(IFinConfig* config, int flag);
/**
* @brief loading
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_show_loading(IFinConfig* config, bool show_loading);
/**
* @brief , 宿exe,
*
*
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_config_set_exe_path(IFinConfig* config, const char* exe_path);
#ifdef _WIN32
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE
finclip_start_applet_embed(int appstore, const char* appid, HWND container);
#endif
#ifdef __cplusplus
/**
* @brief
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE
finclip_register_callback_cpp(IFinConfigPacker* packer, FinClipApiType type,
const char* apis, Callback* callback);
/**
* @brief
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE finclip_invoke_api_cpp(FinClipApiType type,
const char* app_id,
const char* api_name,
const char* params,
Callback* callback);
#endif
#ifdef __cplusplus
}
#endif
#endif /* WRAPPER_SRC_PUBLIC_FINCLIP_API_H_ */

View File

@ -0,0 +1,69 @@
#ifndef SRC_FINCLIP_API_CONST_H_
#define SRC_FINCLIP_API_CONST_H_
#ifndef WRAPPER_SRC_PUBLIC_FINCLIP_API_CONST_H_
#define WRAPPER_SRC_PUBLIC_FINCLIP_API_CONST_H_
#define FIN_SID const char*
#define FIN_OK 0
#define FIN_FAIL 1
#ifdef _WIN32
#include <windows.h>
#define FINCLIP_WINDOW_HANDLE HWND
#elif defined __linux__
#include <gtk/gtk.h>
#define FINCLIP_WINDOW_HANDLE GtkWindow*
#elif defined __APPLE__
typedef struct objc_object* FINCLIP_WINDOW_HANDLE;
#endif
#ifdef _WIN32
#ifndef FINSTDMETHODCALLTYPE
#define FINSTDMETHODCALLTYPE __stdcall
#define DLL_EXPORT _declspec(dllexport)
#endif
#else
#define FINSTDMETHODCALLTYPE
#define DLL_EXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief
* kAsync:
* kBaseLibrarySync:
* kAppletSync:
*/
enum StartFlags {
kAsync = 0,
kBaseLibrarySync = 1 << 0,
kAppletSync = 1 << 1,
};
/**
* @brief APIjssdk
*
*/
typedef enum { kApplet, kWebView } FinClipApiType;
/**
* @brief api
*
*/
typedef void (*FinclipApiCallback)(const char* res);
/**
* @brief api
*
*/
typedef void (*FinclipApiHandle)(const char* event, const char* param,
FinclipApiCallback callback);
#ifdef __cplusplus
}
#endif
#endif /* WRAPPER_SRC_PUBLIC_FINCLIP_API_CONST_H_ */
#endif /* SRC_FINCLIP_API_CONST_H_ */

1
src/npm/.gitignore vendored 100644
View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,8 @@
### 编译
1. npm run configure
2. npm run build
### 运行
node index.js

View File

@ -0,0 +1,55 @@
{
"targets": [
{
"target_name": "_finclip",
"win_delay_load_hook": "true",
"sources": [
"finclip.cpp"
],
"cflags_cc": [
"-std=c++17"
],
'include_dirs': ["<!@(node -p \"require('node-addon-api').include\")"],
'dependencies': ["<!(node -p \"require('node-addon-api').gyp\")"],
"libraries": [
"../../../vendor/win/x64/FinClipSDKWrapper.lib",
],
"defines": ["_UNICODE", "UNICODE", "NAPI_DISABLE_CPP_EXCEPTIONS"],
"copies": [
{
"destination": "<(module_root_dir)/build/Release/",
"files": [
"../../vendor/win/x64/FinClipSDKWrapper.lib",
"../../vendor/win/x64/FinClipSDKWrapper.dll",
"../../vendor/win/x64/finclip.exe",
"../../vendor/win/x64/finclip.exp",
"../../vendor/win/x64/finclip.lib",
"package.json"
]
},
],
"conditions": [
['OS=="mac"', {
"xcode_settings": {
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
"CLANG_CXX_LIBRARY": "libc++",
"CLANG_CXX_LANGUAGE_STANDARD": "c++17",
'MACOSX_DEPLOYMENT_TARGET': '10.14'
}
}],
['OS=="win"', {
"msvs_settings": {
"VCCLCompilerTool": {
"AdditionalOptions": ["-std:c++17", ],
},
},
}]
]
}
],
"msbuild_settings": {
"ClCompile": {
"LanguageStandard": "stdcpp17"
}
}
}

145
src/npm/finclip.cpp 100644
View File

@ -0,0 +1,145 @@
#include "../finclip_api.h"
#include "resource.h"
// Windows Header Files
#include <windows.h>
// #include <node_api.h>
#include <napi.h>
// C RunTime Header Files
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <winuser.h>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <ostream>
#include <sstream>
#include "json.hpp"
#pragma comment(lib, "FinClipSDKWrapper.lib")
#define MAX_LOADSTRING 100
#define IDM_SENDMESSAGE_1 32784
#define IDM_SENDMESSAGE_2 32785
#define IDC_FINCLIP 109
using namespace std;
using json = nlohmann::json;
std::string Utf8Encode(const std::wstring& wstr, int cp = CP_UTF8) {
if (wstr.empty()) return std::string();
int size_needed =
WideCharToMultiByte(cp, 0, &wstr[0], static_cast<int>(wstr.size()),
nullptr, 0, nullptr, nullptr);
std::string str(size_needed, 0);
WideCharToMultiByte(cp, 0, &wstr[0], static_cast<int>(wstr.size()), &str[0],
size_needed, nullptr, nullptr);
return str;
}
// Convert an UTF8 string to a wide Unicode String
std::wstring Utf8Decode(const std::string& str, int cp = CP_UTF8) {
if (str.empty()) return std::wstring();
int size_needed = MultiByteToWideChar(
cp, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
std::wstring wstr(size_needed, 0);
MultiByteToWideChar(cp, 0, &str[0], static_cast<int>(str.size()), &wstr[0],
size_needed);
return wstr;
}
void CustomApi(const char* event, const char* param,
FinclipApiCallback callback) {
std::string data = param;
std::string e = event;
std::string res = R"({"data":"ok"})";
callback(res.c_str());
}
namespace NodeFinClip {
using namespace Napi;
std::string current_appid;
Napi::String start(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Object args = info[0].ToObject();
int handle = args.Get("handle").ToNumber().Int32Value();
int appstore = 1;
string domain("https://finchat-mop-b.finogeeks.club");
string appkey("22LyZEib0gLTQdU3MUauAQVLIkNNhTSGIN42gXzlAsk=");
string appid("60e3c059949a5300014d0c07");
string secret("ae55433be2f62915");
string type("1");
std::string path = args.Get("finclipPath").ToString();
auto* factory = finclip_get_packer_factory();
auto* packer = finclip_packer_factory_get_config_packer(factory);
auto* config = finclip_config_packer_new_config(packer);
finclip_config_packer_add_config(packer, config);
finclip_config_set_app_store(config, appstore);
finclip_config_set_app_key(config, appkey.c_str());
finclip_config_set_secret(config, secret.c_str());
finclip_config_set_domain(config, domain.c_str());
finclip_config_set_start_flag(config, kAppletSync);
finclip_config_set_show_loading(config, false);
finclip_config_set_exe_path(config, path.c_str());
finclip_register_callback(packer, kApplet, "api", CustomApi);
finclip_register_callback(packer, kWebView, "webapi", CustomApi);
finclip_initialize(packer);
finclip_start_applet(appstore, appid.c_str());
// hWnd_container = GetForegroundWindow();
// SetWindowPos(hWnd_container, HWND_TOP, 0, 0, 1024, 768,
// SWP_ASYNCWINDOWPOS);
// // hWnd_container = (HWND) handle;
// // hWnd_container = GetFocus();
// HRESULT hr = StartApplet(
// hWnd_container, appstore, Utf8Encode(wappid).c_str(), "", packer,
// args.Get("finclipPath").ToString().Utf8Value().c_str(),
// FinclipAppletCallback);
current_appid = appid;
finclip_set_position(current_appid.c_str(), 1000, 300, 540, 960);
// SetAppletPos(Utf8Encode(wappid).c_str(), 0, 30, 540, 960, true);
// packer->Release();
return Napi::String::New(env, path);
}
Napi::String close(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
finclip_close_all_applet();
return Napi::String::New(env, "success");
}
Napi::String setAppletPos(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Object args = info[0].ToObject();
int left = args.Get("left").ToNumber().Int32Value();
int top = args.Get("top").ToNumber().Int32Value();
int width = args.Get("width").ToNumber().Int32Value();
int height = args.Get("height").ToNumber().Int32Value();
finclip_set_position(current_appid.c_str(), left, top, width, height);
return Napi::String::New(env, "success");
}
Napi::String createWindow(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::Object args = info[0].ToObject();
CreateWindowW(L"child_finclip", L"test", WS_VISIBLE, 0, 0, 1024, 768, nullptr,
nullptr, nullptr, nullptr);
return Napi::String::New(env, "success");
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "start"), Napi::Function::New(env, start));
exports.Set(Napi::String::New(env, "close"), Napi::Function::New(env, close));
exports.Set(Napi::String::New(env, "setAppletPos"),
Napi::Function::New(env, setAppletPos));
exports.Set(Napi::String::New(env, "createWindow"),
Napi::Function::New(env, createWindow));
return exports;
}
NODE_API_MODULE(addon, Init)
} // namespace NodeFinClip

View File

@ -0,0 +1,3 @@
#pragma once
#include "resource.h"

32
src/npm/index.js 100644
View File

@ -0,0 +1,32 @@
// setTimeout(() => {
const hw = require('./build/Release/_finclip.node');
hw.createWindow({});
console.log('gg')
// console.log(hw.start({
// handle: 41419442,
// finclipPath: `C:\\Users\\gyt\\Code\\FinChat\\local-module\\fincliplib\\finclip.exe`
// }))
// }, 1000 * 6);
// const { Worker } = require('worker_threads');
// const worker = new Worker(`
// const hw = require('./build/Release/_finclip.node');
// setTimeout(() => {
// console.log(hw.start({
// handle: 41419442,
// finclipPath: 'C:\\\\Users\\\\gyt\\\\Code\\\\FinChat\\\\local-module\\\\fincliplib\\\\finclip.exe'
// }))
// }, 1000 * 6);
// setTimeout(() => {
// }, 1000 * 60 * 60);
// `, { eval: true });
// worker.on('message', message => console.log(message));
// worker.postMessage('ping');
setTimeout(() => {
}, 1000 * 60 * 60);

26753
src/npm/json.hpp 100644

File diff suppressed because it is too large Load Diff

3270
src/npm/package-lock.json generated 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
{
"name": "finclip",
"version": "1.0.0",
"description": "",
"main": "./_finclip.node",
"scripts": {
"configure": "node-gyp configure",
"build": "node-gyp build",
"rebuild": "node-gyp rebuild",
"erebuild": "electron-rebuild -v 13.6.6"
},
"devDependencies": {
"electron-rebuild": "^3.2.7",
"node-addon-api": "^1.7.2"
},
"gypfile": true
}

View File

@ -1,3 +0,0 @@
*.zip
/lib
*.bz2

View File

@ -1,394 +0,0 @@
#ifndef __H_FINCLIP_WRAPPER_API_H__
#define __H_FINCLIP_WRAPPER_API_H__
#ifdef _WIN32
# ifndef FINSTDMETHODCALLTYPE
# define FINSTDMETHODCALLTYPE __stdcall
# define DLL_EXPORT _declspec(dllexport)
# endif
#else
# define FINSTDMETHODCALLTYPE
# define DLL_EXPORT
#endif
#define FIN_SID const char*
#define FIN_OK 0
#define FIN_FAIL 1
#include <windows.h>
namespace com::finogeeks::finclip::wrapper {
/**
* @brief
* kAsync:
* kBaseLibrarySync:
* kAppletSync:
*/
enum StartFlags
{
kAsync = 0,
kBaseLibrarySync = 1 << 0,
kAppletSync = 1 << 1,
};
/**
* @brief APIjssdk
*
*/
enum class FinClipApiType
{
kApplet,
kWebView
};
/**
* @brief
*
*/
struct IKnown
{};
/// SDK统一事件接口
/**
* @brief API
{
"size": 100,
"data": [[{},{}...],[{},{}...]]
}
*/
struct IResultSet : public IKnown
{
public:
///取字段数
/**@return 返回字段数.
*/
virtual int GetColCount() = 0;
///取字段名
/** @param column:字段序号(以0为基数)
* @return NULL
*/
virtual const char* GetColName(int column) = 0;
//按字段名,取字段值(字符串)
/**@param columnName: 字段名
*@return ,NULL
*/
virtual const char* GetStr(const char* columnName) = 0;
///取字段名对应的字段序号
/**@param columnName: 字段名
*@return . -1
*/
virtual int FindColIndex(const char* columnName) = 0;
//
//按字段序号(以0为基数),取字段值(字符串)
/**@param column:字段序号(以0为基数)
*@return ,NULL
*/
virtual const char* GetStrByIndex(int column) = 0;
///按字段序号获得字段值,二进制数据
/**@param column: 字段序号(以0为基数)
*@param lpRawLen: [out]
*@return :
*/
virtual void* GetRawByIndex(int column, int* lpRawLen) = 0;
///按字段名,取字段值
/**@param columnName:字段名
*@param lpRawLen: [out]
*@return :
*/
virtual void* GetRaw(const char* columnName, int* lpRawLen) = 0;
///最后一次取的字段值是否为NULL
/**@return 0 是, 1不是
*/
virtual int WasNull() = 0;
///取下一条记录
virtual void Next() = 0;
///判断是否为结尾
/**@return 1 是0 不是;
*/
virtual int IsEOF() = 0;
///判断是否为空
/**@return 1 是0 不是;
*/
virtual int IsEmpty() = 0;
virtual void* Destroy() = 0;
};
/**
* @brief SDK
*
*/
struct IEvent : public IResultSet
{
///取结果集个数
virtual int GetDatasetCount() = 0;
///设置当前结果集
/**
*@param int nIndex
*@return int 0
*/
virtual int SetCurrentDatasetByIndex(int nIndex) = 0;
///结果集行记录游标接口:取结果集的首条记录
virtual void First() = 0;
///结果集行记录游标接口:取结果集的最后一条记录
virtual void Last() = 0;
///结果集行记录游标接口取结果集的第n条记录取值范围[1, GetRowCount()]
virtual void Go(int nRow) = 0;
virtual const char* GetBuffer() = 0;
virtual void Release() = 0;
};
struct IApiCallback
{
public:
virtual void Callback(const char* event) = 0;
};
//函数指针回调
/**
* @params ret 0,1
* @params event IEvent
*
*
*/
typedef void (*FinClipSDKCallback)(IEvent*);
///数据打包器接口
struct IFinPacker : public IKnown
{
public:
/**
* @brief
*/
virtual void BeginPacker() = 0;
/**
* @brief
* @detail KEY,VALUE
*
* @param field
* @param value
* @return 01
*/
virtual void Add(const char* field, const char* value) = 0;
/**
* @brief
*/
virtual void EndPacker() = 0;
/**
* @brief
*/
virtual void Release() = 0;
/**
* @brief
* @return
*/
virtual int GetBufferSize() = 0;
/**
* @brief
* @param buffer
* @param size
* @return 01
*/
virtual int Dump(unsigned char* buffer, int* size) = 0;
};
///配置信息接口
struct IFinConfig
{
public:
/**
*
* SDK;
* domain;
*
*@param app_store
*@return void
*/
virtual void SetAppStore(int app_store) = 0;
/**
* @brief
* @param encrypt_type 0: 1:
* @return void
*/
virtual void SetEncryptType(int encrypt_type) = 0;
/**
* @brief
* @param domain : https://api.finogeeks.com
* @return void
*/
virtual void SetDomain(const char* domain) = 0;
/**
* @brief Api
* @param apiprefix /api/v1/mop
* @return void
*/
virtual void SetApiPrefix(const char* apiprefix) = 0;
/**
* @brief SDK
* @param appkey
* @return void
*/
virtual void SetAppKey(const char* appkey) = 0;
/**
* @brief SDK
* @param secret
* @return void
*/
virtual void SetSecret(const char* secret) = 0;
/**
* @brief SDK
* @param finger
* @return void
*/
virtual void SetFinger(const char* finger) = 0;
/**
* @brief
* @param type 0:1:
* @return void
*/
virtual void SetAppWindowStyle(int type) = 0;
/**
* @brief 线zip
* @param path
* @return void
*/
virtual void SetOfflineBaseLibrary(const char* path) = 0;
/**
* @brief 线zip
* @param path
* @return void
*/
virtual void SetOfflineApplet(const char* path) = 0;
/**
* @brief
* @param type 0:1:
* @return void
*/
virtual void SetShowLoading(int type) = 0;
/**
* @brief
* @param flag: StartFlags
* @return void
*/
virtual void SetStartFlag(int flag) = 0;
};
/*
* api
*/
struct IApi
{
/**
* @brief
*
* @param event
* @param param
* @param callback
*/
virtual void invoke(const char* event, const char* param, IApiCallback* callback) = 0;
/**
* @brief Apiapiwebview api
*
* @return FinClipApiType Api
*/
virtual FinClipApiType GetApiType() const = 0;
/**
* @brief Api
*
* @return char**
*/
virtual const char* apis() = 0;
/**
* @brief Api
*
* @return size_t
*/
virtual size_t size() = 0;
};
///配置打包器接口
struct IFinConfigPacker : public IKnown
{
public:
/**
* @brief
* @return
*/
virtual IFinConfig* NewConfig() = 0;
/**
* @brief
* @return 0
*/
virtual int AddConfig(IFinConfig* config) = 0;
/**
* @brief 使api
* @return 0
*/
virtual int RegisterApi(IApi* config) = 0;
/**
* @brief
* @return
*/
virtual IFinConfig* GetConfig(int type) = 0;
/**
* @brief
* @return
*/
virtual int GetConfigSize() = 0;
/**
* @brief
* @return
*/
virtual IFinConfig* GetConfigByIndex(int index) = 0;
/**
* @brief 使api
* @return 使api
*/
virtual int GetApiSize() = 0;
/**
* @brief 使api
* @return 使api
*/
virtual IApi* GetApiByIndex(int index) = 0;
};
struct IPackerFactory : public IKnown
{
public:
/**
* @brief
* @detail
*
* @return
*/
virtual IFinConfigPacker* GetFinConfigPacker() = 0;
/**
* @brief
* @detail
*
* @return
*/
virtual IFinPacker* GetFinPacker() = 0;
};
} // namespace com::finogeeks::finclip::wrapper
#endif // !__H_FINCLIPAPI_H__

View File

@ -1,104 +0,0 @@
#ifndef __H_FINCLIP_WRAPPER_H__
#define __H_FINCLIP_WRAPPER_H__
#include "finclip_api.h"
#include <windows.h>
namespace com::finogeeks::finclip::wrapper {
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SDI
* @detail
*
* @param hinstance
* @param configpacker
* @return 01
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE Initialize(HINSTANCE hinstance, IFinConfigPacker* configpacker);
/**
* @brief
* @detail
*
* @param
* @param
* @return
* @retval
* @note
* @attention
* @warning
* @exception
*/
DLL_EXPORT IPackerFactory* FINSTDMETHODCALLTYPE GetPackerFactory();
/**
* @brief
* @detail
*
* @param
* @param
* @return
* @retval
* @note
* @attention
* @warning
* @exception
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE CloseAllApplet();
/**
* @brief
* @detail
*
* @param
* @param
* @return
* @retval
* @note
* @attention
* @warning
* @exception
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE CleanCache();
///小程序Api
/**打开小程序
*
* @param appstore
* @param appId appId
* @param param
* @param callback
* @param exe_path : finclip.exe, d:\finclip.exe
* @return 01
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE StartApplet(HWND hWnd, int appstore, const char* appid, const char* page_path,
IFinPacker* params, const char* exe_path, FinClipSDKCallback callback);
/**
* @brief Set the Applet Pos object
*
* @param appid
* @param appstore
* @param left
* @param top
* @param width
* @param height
* @return DLL_EXPORT
*/
DLL_EXPORT void FINSTDMETHODCALLTYPE SetAppletPos(const char* appid, int left, int top, int width, int height,
bool repaint);
/**
* @brief
*
* @return DLL_EXPORT
*/
DLL_EXPORT int FINSTDMETHODCALLTYPE FinClipShutdown();
DLL_EXPORT int FINSTDMETHODCALLTYPE InvokeWebApi(const char* app_id, const char* api_name, const char* params);
DLL_EXPORT int FINSTDMETHODCALLTYPE CloseApplet(const char* appid);
#ifdef __cplusplus
}
#endif
} // namespace com::finogeeks::finclip::wrapper
#endif

0
vendor/mac/README.md vendored 100644
View File

2
vendor/win/.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
x86/
x64/

0
vendor/win/README.md vendored 100644
View File