Jiang's Tech Journal

Jiang's Tech Journal

首页
分类
关于
Login →
Jiang's Tech Journal

Jiang's Tech Journal

首页 分类 关于
Login
  1. Home
  2. Electron
  3. Electron界面嵌入其他exe程序

Electron界面嵌入其他exe程序

0
  • Electron
  • Published at 2024-11-30
  • Read 215 times
Jiang
Jiang
Table of Contents
No Table of Contents
import { app, BrowserWindow } from 'electron';
import path from 'path';
import { exec, spawn } from 'child_process';
import koffi from 'koffi';
import { endianness } from 'os';

const user32 = koffi.load('user32.dll');
const DWORD = koffi.alias('DWORD', 'uint32_t');
const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
const HWND = koffi.alias('HWND', HANDLE);
const BOOL = koffi.alias('BOOL', 'int');
const LONG = koffi.alias('LONG', 'int');

const SetParent = user32.func('__stdcall', 'SetParent', 'int', ['int', 'int']);
const MoveWindow = user32.func('__stdcall', 'MoveWindow', 'bool', ['int', 'int', 'int', 'int', 'int', 'bool']);
const SetWindowPos = user32.func('__stdcall', 'SetWindowPos', 'bool', ['int', 'int', 'int', 'int', 'int', 'int', 'int']);
const GetWindowThreadProcessId = user32.func('DWORD __stdcall GetWindowThreadProcessId(HWND hWnd, _Out_ DWORD *lpdwProcessId)');
const SetWindowLong = user32.func('LONG __stdcall SetWindowLongA(HWND hWnd, int nIndex, LONG dwNewLong)');

const EnumWindowsProc = koffi.proto('bool __stdcall EnumWindowsProc(int, long lParam)');
const EnumWindows = user32.func('__stdcall', 'EnumWindows', 'bool', [koffi.pointer(EnumWindowsProc), 'int']);

async function GetHwndFromPid(window_pid, retry = 0) {
    const hwnds = [];
    const cb = koffi.register((hwnd, lParam) => {
        hwnds.push(hwnd);
        return true;
    }, koffi.pointer(EnumWindowsProc));

    EnumWindows(cb, 0);

    koffi.unregister(cb);

    const data = hwnds
        .map((hwnd) => {
            const buffer = Buffer.alloc(4);
            GetWindowThreadProcessId(hwnd, buffer);
            return {
                hwnd,
                pid: buffer.readInt32LE()
            };
        })
        .find((item) => item.pid === window_pid);

    if (data) {
        return data.hwnd;
    } else {
        if (retry < 100) {
            return await new Promise((resolve) => {
                setTimeout(() => {
                    resolve(GetHwndFromPid(window_pid, retry + 1));
                }, 100);
            });
        } else {
            return null;
        }
    }
}

async function StartProcess(child_window, main_hwnd) {
    const handler = endianness() == 'LE' ? main_hwnd.readInt32LE() : main_hwnd.readInt32BE();

    // --window-borderless
    // --fullscreen
    // --keyboard=uhid
    const child = spawn('F:\\Soft\\scrcpy-win64-v2.6.1\\scrcpy.exe', ['--fullscreen', '--video-codec=h265', '--video-bit-rate=16M', '--max-fps=60'], {
        windowsVerbatimArguments: true
    });

    console.log('child.pid:', child.pid);
    const hwnd = await GetHwndFromPid(child.pid);
    console.log('hwnd:', hwnd);

    if (hwnd) {
        SetParent(hwnd, handler);
        MoveWindow(hwnd, 0, 0, 300 - 10, 660 - 32 - 10, true);
        SetWindowPos(hwnd, -1, 0, 0, 0, 0, 0x0001 | 0x0002 | 0x0040);

        child_window.on('resize', () => {
            const bounds = child_window.getBounds();
            MoveWindow(hwnd, 0, 0, bounds.width - 10, bounds.height - 32 - 10, true);

            // 如果窗口渲染了html,移动的时候需要重新设置一下,不然无法点击
            setTimeout(() => {
                SetParent(hwnd, handler);
            }, 1000);
        });
    } else {
        console.log('hwnd is null');
    }
}

function createWindow() {
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        center: true,
        backgroundColor: '#00FFFFFF'
    });

    mainWindow.loadURL(`${process.env.ELECTRON_RENDERER_URL}/index.html`);

    // StartProcess(mainWindow, mainWindow.getNativeWindowHandle());

    const child_window = new BrowserWindow({
        parent: mainWindow,
        modal: true,
        autoHideMenuBar: true,
        width: 300,
        height: 660,
        center: true,
        transparent: true,
        backgroundColor: '#00FFFFFF' //00FFFFFF
    });

    StartProcess(child_window, child_window.getNativeWindowHandle());
}

app.whenReady().then(() => {
    createWindow();

    app.on('activate', function () {
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
});

app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') app.quit();
});

Related Posts

[electron] 一个优雅简单的electron-ipc管理示例

布布子写的electron-ipc管理示例。 Github:https://github.com/ybubuzi/violet-electron-ipc 离线文件:https://download.jiang.in/f/DJS3/violet-electron-ipc-main.zip

electron、nest的权限管理

electron部分

Electron界面嵌入其他exe程序

import { app, BrowserWindow } from 'electron'; import path from 'path'; import { exec, spawn } from 'child_process'; import koffi from 'koffi'; import

electron使用webview 链接跳转,阻止创建新窗口

//入口文件 <webview src="https://www.baidu.com/" allowpopups ></webview> const { app, } = require("electron"); //监听webview新建的窗口 app.on(

Sqlite3打包后无法运行,报Cannot find module sqlite3

删除node_modules,重新运行npm i 运行npm install出现vs未找到问题 vs2015_构建工具 使用vs_installer下载安装C++ 桌面开发组件 在右侧列表中选定windows sdk,注意版本,该文编写时安装sdk版本为10.0.2

Electron终端中文乱码解决方案

在启动命令之前添加chcp 65001解决electron控制台下打印中文乱码 "dev": "chcp 65001 && electron-vite dev"

Table of Contents
No Table of Contents
Copyright © 2024 your company All Rights Reserved. Powered by Halo.