使用nodejs获取指定应用窗口的截图,代码是否还有啥优化空间,重点是执行效率和资源释放问题?

请大神帮看看下面的代码,感觉资源没有正确释放,或者代码是否存在明显漏洞等。

const ffi = require('ffi-napi');
const ref = require('ref-napi');
const Struct = require('ref-struct-di')(ref);
const { createCanvas } = require('canvas');
const fs = require('fs');
// 定义结构体
const RECT = Struct({
    'left': 'long',
    'top': 'long',
    'right': 'long',
    'bottom': 'long'
});
const BITMAPINFOHEADER = Struct({
    'biSize': 'uint32',
    'biWidth': 'int32',
    'biHeight': 'int32',
    'biPlanes': 'uint16',
    'biBitCount': 'uint16',
    'biCompression': 'uint32',
    'biSizeImage': 'uint32',
    'biXPelsPerMeter': 'int32',
    'biYPelsPerMeter': 'int32',
    'biClrUsed': 'uint32',
    'biClrImportant': 'uint32'
});
// 定义常量
const SRCCOPY = 0xCC0020;
// 定义库函数
const user32 = ffi.Library('user32', {
    'FindWindowA': ['long', ['string', 'string']], // 查找窗口句柄
    'GetDC': ['long', ['long']], // 获取设备上下文
    'ReleaseDC': ['long', ['long', 'long']], // 释放设备上下文
    'GetWindowRect': ['bool', ['long', ref.refType(RECT)]] // 获取窗口位置
});
const gdi32 = ffi.Library('gdi32', {
    'CreateCompatibleDC': ['long', ['long']], // 创建兼容的设备上下文
    'CreateDIBSection': ['long', ['long', ref.refType(BITMAPINFOHEADER), 'uint', ref.refType(ref.refType('void')), 'long', 'ulong']], // 创建设备无关位图的内存缓冲区
    'SelectObject': ['long', ['long', 'long']], // 选入对象到设备上下文中
    'BitBlt': ['long', ['long', 'int', 'int', 'int', 'int', 'long', 'int', 'int', 'ulong']], // 复制位图到另一个设备上下文中
    'DeleteObject': ['long', ['long']], // 删除对象
    'DeleteDC': ['bool', ['int32']], // 删除设备上下文
});
// 查找窗口句柄
const hWnd = user32.FindWindowA(null, 'Windows PowerShell');
console.log('hWnd---', hWnd)
// 获取窗口位置
const rect = new RECT();
user32.GetWindowRect(hWnd, rect.ref());
const width = rect.right - rect.left;
const height = rect.bottom - rect.top;
console.log('left:', rect.left);
console.log('top:', rect.top);
console.log('width:', width);
console.log('height:', height);
// 获取设备上下文
const hdcScreen = user32.GetDC(hWnd);
// 创建兼容的设备上下文
const hdcBlt = gdi32.CreateCompatibleDC(hdcScreen);
// 创建设备无关位图的内存缓冲区
const bmiHeader = new BITMAPINFOHEADER({
    'biSize': BITMAPINFOHEADER.size,
    'biWidth': width,
    'biHeight': -height,
    'biPlanes': 1,
    'biBitCount': 32,
    'biCompression': 0,
    'biSizeImage': 0,
    'biXPelsPerMeter': 0,
    'biYPelsPerMeter': 0,
    'biClrUsed': 0,
    'biClrImportant': 0
});
const ppvBits = ref.alloc(ref.refType('void'));
const hBitmap = gdi32.CreateDIBSection(hdcScreen, bmiHeader.ref(), 0, ppvBits, 0, 0);
// 选入对象到设备上下文中
gdi32.SelectObject(hdcBlt, hBitmap);

// 复制位图到另一个设备上下文中
// gdi32.BitBlt(hdcBlt, 0, 0, width, height, hdcScreen, rect.left, rect.top, SRCCOPY);
gdi32.BitBlt(hdcBlt, 0, 0, width, height, hdcScreen, -10, -10, SRCCOPY);

// 将位图数据转换成canvas可用的imageData格式
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(width, height);
const buffer = Buffer.from(ref.reinterpret(ppvBits.deref(), width * height * 4));
for (let i = 0; i < width * height * 4; i += 4) {
    imageData.data[i] = buffer[i + 2];
    imageData.data[i + 1] = buffer[i + 1];
    imageData.data[i + 2] = buffer[i];
    imageData.data[i + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
// 将canvas转换成PNG格式并保存
const out = fs.createWriteStream('screenshot3434343.png');
const stream = canvas.createPNGStream();
stream.pipe(out).on('finish', () => {
    console.log('The PNG file was saved!');
});
// 删除对象和设备上下文
gdi32.DeleteObject(hBitmap);
user32.ReleaseDC(hWnd, hdcScreen);
gdi32.DeleteDC(hdcBlt);
阅读 3.2k
1 个回答
// 错误检查
if (hWnd === 0) {
    console.error("窗口未找到");
    return;
}

// ...

// 释放原始设备上下文
user32.ReleaseDC(hWnd, hdcScreen);

// ...

// 删除对象和设备上下文
gdi32.DeleteObject(hBitmap);
gdi32.DeleteDC(hdcBlt); // 用DeleteDC释放兼容DC

// 关闭文件流
out.end(() => {
    console.log('The PNG file was saved!');
});
推荐问题
logo
Microsoft
子站问答
访问
宣传栏