mirror of
https://github.com/HolographicHat/Yae.git
synced 2025-12-14 02:18:13 +08:00
native addon
This commit is contained in:
1
native.d.ts
vendored
1
native.d.ts
vendored
@@ -1,2 +1,3 @@
|
|||||||
export function selectGameExecutable(): string
|
export function selectGameExecutable(): string
|
||||||
export function checkGameIsRunning(processName: string): boolean
|
export function checkGameIsRunning(processName: string): boolean
|
||||||
|
export function whoUseThePort(port: number): object
|
||||||
|
|||||||
@@ -8,6 +8,18 @@
|
|||||||
"utils.h",
|
"utils.h",
|
||||||
"define.h"
|
"define.h"
|
||||||
],
|
],
|
||||||
|
"cflags!": [
|
||||||
|
"-fno-exceptions"
|
||||||
|
],
|
||||||
|
"cflags_cc!": [
|
||||||
|
"-fno-exceptions"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"NAPI_DISABLE_CPP_EXCEPTIONS"
|
||||||
|
],
|
||||||
|
"include_dirs": [
|
||||||
|
"<!(node -p \"require('node-addon-api').include_dir\")"
|
||||||
|
],
|
||||||
"msvs_settings": {
|
"msvs_settings": {
|
||||||
"VCCLCompilerTool": {
|
"VCCLCompilerTool": {
|
||||||
"AdditionalOptions": [
|
"AdditionalOptions": [
|
||||||
|
|||||||
@@ -2,25 +2,13 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <napi.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
#include <node_api.h>
|
|
||||||
|
|
||||||
using std::string, std::wstring, std::cout, std::endl;
|
using std::string, std::wstring, std::cout, std::to_string;
|
||||||
|
using Napi::Object, Napi::Env, Napi::Function, Napi::Value, Napi::CallbackInfo, Napi::TypeError, Napi::Error;
|
||||||
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
|
typedef unsigned long ul;
|
||||||
typedef unsigned long long ull;
|
typedef unsigned long long ull;
|
||||||
|
|
||||||
typedef napi_env Env;
|
|
||||||
typedef napi_value Value;
|
|
||||||
typedef napi_status Status;
|
|
||||||
typedef napi_callback Callback;
|
|
||||||
typedef napi_callback_info CallbackInfo;
|
|
||||||
|
|
||||||
#define GetBoolean napi_get_boolean
|
|
||||||
#define ThrowError napi_throw_error
|
|
||||||
#define GetUTF8String napi_get_value_string_utf8
|
|
||||||
#define CreateFunction napi_create_function
|
|
||||||
#define GetCallbackInfo napi_get_cb_info
|
|
||||||
#define CreateUTF8String napi_create_string_utf8
|
|
||||||
#define SetNamedProperty napi_set_named_property
|
|
||||||
|
|||||||
@@ -1,58 +1,96 @@
|
|||||||
#include <string>
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "define.h"
|
#include "define.h"
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#pragma comment(lib,"ws2_32.lib")
|
||||||
|
#pragma comment(lib,"iphlpapi.lib")
|
||||||
|
|
||||||
namespace native {
|
namespace native {
|
||||||
|
|
||||||
Value checkGameIsRunning(Env env, CallbackInfo info) {
|
Value checkGameIsRunning(const CallbackInfo &info) {
|
||||||
ull argc = 0;
|
Env env = info.Env();
|
||||||
Value args[1];
|
if (info.Length() != 1 || !info[0].IsString()) {
|
||||||
if (GetCallbackInfo(env, info, &argc, args, nullptr, nullptr) != napi_ok) {
|
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
|
||||||
return nullptr;
|
return env.Null();
|
||||||
}
|
}
|
||||||
char nameBuffer[256];
|
wstring name = StringToWString(info[0].As<Napi::String>().Utf8Value());
|
||||||
GetUTF8String(env, args[0], (char *) &nameBuffer, sizeof(nameBuffer), nullptr);
|
|
||||||
wstring pn = StringToWString(nameBuffer);
|
|
||||||
bool isRunning = false;
|
bool isRunning = false;
|
||||||
PROCESSENTRY32 entry;
|
PROCESSENTRY32 entry;
|
||||||
entry.dwSize = sizeof(entry);
|
entry.dwSize = sizeof(entry);
|
||||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
||||||
if (Process32First(snapshot, &entry) == TRUE) {
|
if (Process32First(snapshot, &entry) == TRUE) {
|
||||||
while (Process32Next(snapshot, &entry) == TRUE) {
|
while (Process32Next(snapshot, &entry) == TRUE) {
|
||||||
if (wstring(entry.szExeFile) == pn) {
|
if (wstring(entry.szExeFile) == name) {
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(snapshot);
|
CloseHandle(snapshot);
|
||||||
Value ret;
|
return Napi::Boolean::New(env, isRunning);
|
||||||
GetBoolean(env, isRunning, &ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value selectGameExecutable(Env env, CallbackInfo args) {
|
Value selectGameExecutable(const CallbackInfo &info) {
|
||||||
Value path;
|
Env env = info.Env();
|
||||||
LSTATUS retcode = OpenFile(env, path);
|
Napi::String path;
|
||||||
if (retcode != ERROR_SUCCESS) {
|
if (OpenFile(env, path) != ERROR_SUCCESS) {
|
||||||
SetLastError(retcode);
|
Error::New(env, "Failed to open file: " + to_string(CommDlgExtendedError())).ThrowAsJavaScriptException();
|
||||||
return nullptr;
|
return env.Null();
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value init(Env env, Value exports) {
|
Value whoUseThePort(const CallbackInfo &info) {
|
||||||
EnablePrivilege(L"SeDebugPrivilege");
|
Env env = info.Env();
|
||||||
if (RegisterFunction(env, exports, checkGameIsRunning, "checkGameIsRunning") != napi_ok) {
|
if (info.Length() != 1 || !info[0].IsNumber()) {
|
||||||
ThrowError(env, nullptr, "Failed to register checkGameIsRunning");
|
TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException();
|
||||||
return nullptr;
|
return env.Null();
|
||||||
}
|
}
|
||||||
if (RegisterFunction(env, exports, selectGameExecutable, "selectGameExecutable") != napi_ok) {
|
DWORD dwSize = 0;
|
||||||
ThrowError(env, nullptr, "Failed to register selectGameExecutable");
|
PMIB_TCPTABLE_OWNER_PID pTcpTable = nullptr;
|
||||||
return nullptr;
|
GetExtendedTcpTable(pTcpTable, &dwSize, TRUE,AF_INET,TCP_TABLE_OWNER_PID_ALL,0);
|
||||||
|
pTcpTable = (PMIB_TCPTABLE_OWNER_PID)new byte[dwSize];
|
||||||
|
if(GetExtendedTcpTable(pTcpTable,&dwSize,TRUE,AF_INET,TCP_TABLE_OWNER_PID_ALL,0) != NO_ERROR) {
|
||||||
|
Error::New(env, "GetExtendedTcpTable failed").ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
}
|
}
|
||||||
|
int port = info[0].As<Napi::Number>().Int32Value();
|
||||||
|
auto nNum = (int)pTcpTable->dwNumEntries;
|
||||||
|
DWORD pid = 0;
|
||||||
|
for(int i = 0; i < nNum; i++) {
|
||||||
|
if (htons(pTcpTable->table[i].dwLocalPort) == port) {
|
||||||
|
pid = pTcpTable->table[i].dwOwningPid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete pTcpTable;
|
||||||
|
Value ret = env.Null();
|
||||||
|
if (pid != 0) {
|
||||||
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||||
|
if (hProcess == nullptr) {
|
||||||
|
Error::New(env, "OpenProcess error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
TCHAR fnBuf[MAX_PATH];
|
||||||
|
DWORD length = MAX_PATH;
|
||||||
|
if (QueryFullProcessImageName(hProcess, 0, fnBuf, &length) == 0) {
|
||||||
|
Error::New(env, "QueryFullProcessImageName error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||||
|
return env.Null();
|
||||||
|
}
|
||||||
|
Object obj = Object::New(env);
|
||||||
|
obj.Set("pid", Napi::Number::New(env, pid));
|
||||||
|
obj.Set("path", Napi::String::New(env, WStringToString(fnBuf)));
|
||||||
|
ret = obj;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object init(Env env, Object exports) {
|
||||||
|
EnablePrivilege(env, L"SeDebugPrivilege");
|
||||||
|
exports.Set("whoUseThePort", Function::New(env, whoUseThePort));
|
||||||
|
exports.Set("checkGameIsRunning", Function::New(env, checkGameIsRunning));
|
||||||
|
exports.Set("selectGameExecutable", Function::New(env, selectGameExecutable));
|
||||||
return exports;
|
return exports;
|
||||||
}
|
}
|
||||||
|
|
||||||
NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
|
NODE_API_MODULE(addon, init)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,8 @@
|
|||||||
"gypfile": true,
|
"gypfile": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"node-gyp": "^9.0.0"
|
"node-gyp": "^9.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^4.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,17 @@ string WStringToString(const wstring &src) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LSTATUS OpenFile(Env env, Value &result, HWND parent) {
|
void Log(Env env, const string &msg) {
|
||||||
|
auto logFunc = env.Global().Get("console").As<Object>().Get("log").As<Function>();
|
||||||
|
logFunc.Call({ Napi::String::New(env, msg) });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(Env env, const wstring &msg) {
|
||||||
|
auto logFunc = env.Global().Get("console").As<Object>().Get("log").As<Function>();
|
||||||
|
logFunc.Call({ Napi::String::New(env, WStringToString(msg)) });
|
||||||
|
}
|
||||||
|
|
||||||
|
LSTATUS OpenFile(Env env, Napi::String &result, HWND parent) {
|
||||||
OPENFILENAME open;
|
OPENFILENAME open;
|
||||||
ZeroMemory(&open, sizeof(open));
|
ZeroMemory(&open, sizeof(open));
|
||||||
WCHAR file[32768];
|
WCHAR file[32768];
|
||||||
@@ -36,30 +46,17 @@ LSTATUS OpenFile(Env env, Value &result, HWND parent) {
|
|||||||
open.lpstrFilter = L"国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0";
|
open.lpstrFilter = L"国服/国际服主程序 (YuanShen/GenshinImpact.exe)\0YuanShen.exe;GenshinImpact.exe\0";
|
||||||
open.lStructSize = sizeof(open);
|
open.lStructSize = sizeof(open);
|
||||||
if(GetOpenFileName(&open)) {
|
if(GetOpenFileName(&open)) {
|
||||||
string s = WStringToString(file);
|
result = Napi::String::New(env, WStringToString(file));
|
||||||
if (CreateUTF8String(env, s.c_str(), NAPI_AUTO_LENGTH, &result) == napi_ok) {
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
return ERROR_ERRORS_ENCOUNTERED;
|
return ERROR_ERRORS_ENCOUNTERED;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return (LSTATUS)CommDlgExtendedError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Status RegisterFunction(Env env, Value exports, Callback cb, const string &name) {
|
BOOL EnablePrivilege(Env env, const wstring &name) {
|
||||||
Value fn;
|
|
||||||
Status status = CreateFunction(env, nullptr, 0, cb, nullptr, &fn);
|
|
||||||
if (status != napi_ok) return status;
|
|
||||||
status = SetNamedProperty(env, exports, name.c_str(), fn);
|
|
||||||
if (status != napi_ok) return status;
|
|
||||||
return napi_ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL EnablePrivilege(const wstring &name) {
|
|
||||||
HANDLE hToken;
|
HANDLE hToken;
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
||||||
cout << "OpenProcessToken error: %lu\n" << GetLastError() << endl;
|
Error::New(env, "OpenProcessToken error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
TOKEN_PRIVILEGES tp;
|
TOKEN_PRIVILEGES tp;
|
||||||
@@ -67,15 +64,15 @@ BOOL EnablePrivilege(const wstring &name) {
|
|||||||
tp.PrivilegeCount = 1;
|
tp.PrivilegeCount = 1;
|
||||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
if (!LookupPrivilegeValue(nullptr, name.c_str(), &tp.Privileges[0].Luid)) {
|
if (!LookupPrivilegeValue(nullptr, name.c_str(), &tp.Privileges[0].Luid)) {
|
||||||
cout << "LookupPrivilegeValue error: %lu\n" << GetLastError() << endl;
|
Error::New(env, "LookupPrivilegeValue error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, nullptr)) {
|
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, nullptr)) {
|
||||||
cout << "AdjustTokenPrivileges error: %lu\n" << GetLastError() << endl;
|
Error::New(env, "AdjustTokenPrivileges error: " + to_string(GetLastError())).ThrowAsJavaScriptException();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
|
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
|
||||||
cout <<"The token does not have the specified privilege." << endl;
|
Error::New(env, "The token does not have the specified privilege.").ThrowAsJavaScriptException();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
CloseHandle(hToken);
|
CloseHandle(hToken);
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
string WStringToString(const wstring &src);
|
string WStringToString(const wstring &src);
|
||||||
wstring StringToWString(const string &src);
|
wstring StringToWString(const string &src);
|
||||||
LSTATUS OpenFile(Env env, Value &result, HWND parent = GetConsoleWindow());
|
LSTATUS OpenFile(Env env, Napi::String &result, HWND parent = GetConsoleWindow());
|
||||||
Status RegisterFunction(Env env, Value exports, Callback cb, const string &name);
|
BOOL EnablePrivilege(Env env, const wstring &name);
|
||||||
BOOL EnablePrivilege(const wstring &name);
|
void Log(Env env, const string &msg);
|
||||||
|
void Log(Env env, const wstring &msg);
|
||||||
|
|
||||||
#ifndef GENSHIN_EXPORT_NATIVE_UTILS_H
|
#ifndef GENSHIN_EXPORT_NATIVE_UTILS_H
|
||||||
#define GENSHIN_EXPORT_NATIVE_UTILS_H
|
#define GENSHIN_EXPORT_NATIVE_UTILS_H
|
||||||
|
|||||||
Reference in New Issue
Block a user