nodejs调用delphi编写的dll中,使用了dll调用windows api转读取文件属性,感觉使用nodejs也可直接调用windows api。

此处需用到windows系统的version.dll,该dll位于C:\WINDOWS\System32\下,是一个32位的dll,故此处直接使用32位版本的node。

一、安装所需模块(node-gyp、ffi、ref、iconv-lite)

npm install node-gyp -g
npm install ffi -- save
npm install ref --save
npm install iconv-lite --save

其中:node-gyp直接全局安装,ffi、ref、iconv-lite安装在项目中即可

PS:

1. ffi与ref的安装需要用到python,需先装好。

2. ffi用来调用dll

3. ref用来设置buffer

4. iconv-lite用来转码GBK字符

二、示例,使用nodejs读取文件属性

 const ffi = require('ffi');
const ref = require('ref');
const iconvLite = require('iconv-lite'); // 定义dll
const version = ffi.Library('C://WINDOWS//System32//version', {
'GetFileVersionInfoSizeA': [ 'int', ['string', 'int'] ],
'GetFileVersionInfoA': ['int', ['string', 'int', 'int', ref.refType(ref.types.char)]],
'VerQueryValueA': ['int', [ref.refType(ref.types.char), 'string', ref.refType(ref.types.CString), ref.refType('int')]]
}); const Int16Format4 = function (num) {
const s = '0000';
const f = num.toString(16);
return s.substr(0, 4 - f.length) + f;
}; try {
console.log('Begin Test');
// 转码,windows使用AnsiChar,利用iconv-lite使用gbk解码
const file = iconvLite.encode('C:\\Program Files (x86)\\Tencent\\WeChat\\WeChat.exe', 'gbk'); // 获取文件属性大小
const size = version.GetFileVersionInfoSizeA(file, 0);
console.log('fileInfoSize: ' + size); // 读取文件属性buffer
const buf = new Buffer(size);
buf.type = ref.types.char;
version.GetFileVersionInfoA(file, 0, size, buf); // 读取文件属性的LanguageID和CodePage,用来合成属性查找标记
const table = ref.alloc('int32').ref(), length = ref.alloc('int');
version.VerQueryValueA(buf, '\\VarFileInfo\\Translation', table, length);
const tableBuf = table.deref(); // 其中tableBuf中的值应为int32
const codePage = tableBuf.readUInt16LE(0); // codePage应取tableBuf的高16位
const languageID = tableBuf.readUInt16LE(2); // languageID应取tableBuf的低16位
console.log('codePage: ' + codePage.toString(16));
console.log('languageID: ' + languageID.toString(16)); // 合成属性查找标记
// 不同的语言地区,该值可能不一样,据我所知,中文"\\StringFileInfo\\080403A8\\"、英文"\\StringFileInfo\\040904E4\\",故需通过该方式合成最可靠
const pre = '\\StringFileInfo\\' + Int16Format4(codePage) + Int16Format4(languageID) + '\\';
console.log('pre: ' + pre); const versionBuf = new Buffer(1000).ref();
version.VerQueryValueA(buf, pre + 'FileVersion', versionBuf, length);
const infoBuf = versionBuf.deref().slice(0, length.deref());
const info = iconvLite.decode(infoBuf, 'gbk');
console.log('FileVersion: ' + info);
console.log('End Test');
} catch(err) {
console.log(err);
}

运行结果如下:

PS:

1. 传参file最好使用gbk或者gb2312解码,否则如果file中含有中文时,将无法正确读到size、buf

2. versionBuf应尽量给的长一些,再通过length截断,避免数据取值不全

3. pre最好使用这种方式合成得到,否则可能存在读不到属性的情况

三、稍微改写上述代码

 'use strict';

 /**
*
*
* @author Mai
* @date 2018/7/12
* @version
*/ const ffi = require('ffi');
const ref = require('ref');
const iconvLite = require('iconv-lite'); // 定义dll
const version = ffi.Library('C://WINDOWS//System32//version', {
'GetFileVersionInfoSizeA': [ 'int', ['string', 'int'] ],
'GetFileVersionInfoA': ['int', ['string', 'int', 'int', ref.refType(ref.types.char)]],
'VerQueryValueA': ['int', [ref.refType(ref.types.char), 'string', ref.refType(ref.types.CString), ref.refType('int')]]
}); const FileVersion = function () {};
const proto = FileVersion.prototype; // 16进制format(%4.x)
proto._int16Format4 = function (num) {
const s = '0000';
const f = num.toString(16);
return s.substr(0, 4 - f.length) + f;
}; // 根据属性名读取文件属性
proto._getInfo = function (buf, pre, name) {
const infoBufPointer = new Buffer(1000).ref(); // 定义指向Buffer地址的指针,Buffer尽量定义长一点
const length = ref.alloc('int'); // 定义指向整数的指针
if (version.VerQueryValueA(buf, pre + name, infoBufPointer, length) !== 0) {
// 根据length,在Buf中截取属性
const infoBuf = infoBufPointer.deref().slice(0, length.deref() - 1);
return iconvLite.decode(infoBuf, 'gbk');
} else {
return undefined;
}
}; // 获取属性查找标记
proto._getPre = function (buf) {
// 读取文件属性的LanguageID和CodePage,用来合成属性查找标记
const table = ref.alloc('int32').ref(), length = ref.alloc('int');
version.VerQueryValueA(buf, '\\VarFileInfo\\Translation', table, length);
const tableBuf = table.deref(); // 其中tableBuf中的值应为int32
const codePage = tableBuf.readUInt16LE(0); // codePage应取tableBuf的高16位
const languageID = tableBuf.readUInt16LE(2); // languageID应取tableBuf的低16位
// 合成属性查找标记
// 不同的语言,该值不一样,其中英文是"\\StringFileInfo\\080403A8\\",中文是"\\StringFileInfo\\040904E4\\",需通过该方式合成
return '\\StringFileInfo\\' + this._int16Format4(codePage) + this._int16Format4(languageID) + '\\';
}; // 读取文件属性
proto.getFileVersionInfo = function (path) {
// 转码,windows使用AnsiChar,利用iconv-lite使用gb2312解码
const file = iconvLite.encode(path, 'gb2312');
// 获取文件属性大小
const size = version.GetFileVersionInfoSizeA(file, 0); // 读取文件属性buffer
const buf = new Buffer(size);
buf.type = ref.types.char;
version.GetFileVersionInfoA(file, 0, size, buf); // 获取文件属性查找标记
const pre = this._getPre(buf); // 读取文件属性
const fileVersionInfo = {};
fileVersionInfo.CompanyName = this._getInfo(buf, pre, 'CompanyName');
fileVersionInfo.FileDescription = this._getInfo(buf, pre, 'FileDescription');
fileVersionInfo.FileVersion = this._getInfo(buf, pre, 'FileVersion');
fileVersionInfo.InternalName = this._getInfo(buf, pre, 'InternalName');
fileVersionInfo.LegalCopyright = this._getInfo(buf, pre, 'LegalCopyright');
fileVersionInfo.LegalTrademarks = this._getInfo(buf, pre, 'LegalTrademarks');
fileVersionInfo.OriginalFilename = this._getInfo(buf, pre, 'OriginalFilename');
fileVersionInfo.ProductName = this._getInfo(buf, pre, 'ProductName');
fileVersionInfo.ProductVersion = this._getInfo(buf, pre, 'ProductVersion');
fileVersionInfo.Comments = this._getInfo(buf, pre, 'Comments');
return fileVersionInfo;
}; module.exports = FileVersion;

测试代码:

 const FileVersion = require('./versionInfo');

 try {
const fileVersionReader = new FileVersion();
const info = fileVersionReader.getFileVersionInfo('C:\\Program Files (x86)\\Tencent\\WeChat\\WeChat.exe', 'gb2312');
console.log(info);
} catch (err) {
console.log(err);
}

测试结果如下:

参考:

NodeJS和NW通过ffi调用dll/so动态库

通过ffi在node.js中调用动态链接库

nodejs利用windows API读取文件属性(dll)的更多相关文章

  1. 利用 Windows API Code Pack 修改音乐的 ID3 信息

    朋友由于抠门 SD 卡买小了,结果音乐太多放不下,又不舍得再买新卡,不得已决定重新转码,把音乐码率压低一点,牺牲点音质来换空间(用某些人的话说,反正不是搞音乐的,听不出差别)… 结果千千静听(百度音乐 ...

  2. Windows API学习---插入DLL和挂接API

    插入DLL和挂接API 在Microsoft Windows中,每个进程都有它自己的私有地址空间.当使用指针来引用内存时,指针的值将引用你自己进程的地址空间中的一个内存地址.你的进程不能创建一个其引用 ...

  3. 利用windows api共享内存通讯

    主要涉及CreateFile,CreateFileMapping,GetLastError,MapViewOfFile,sprintf,OpenFileMapping,CreateProcess Cr ...

  4. C#利用Windows API 实现关机、注销、重启等操作

    using System; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; nam ...

  5. 【整理】c# 调用windows API(user32.dll)

    User32.dll提供了很多可供调用的接口,大致如下(转自http://blog.csdn.net/zhang399401/article/details/6978803) using System ...

  6. 后端Nodejs利用node-xlsx模块读取excel

    后端Nodejs(利用node-xlsx模块) /** * Created by zh on 16-9-14. */ var xlsx = require("node-xlsx") ...

  7. 【转】c# 调用windows API(user32.dll)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.R ...

  8. Windows API Hooking in Python

    catalogue . 相关基础知识 . Deviare API Hook Overview . 使用ctypes调用Windows API . pydbg . winappdbg . dll inj ...

  9. Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术

    catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...

随机推荐

  1. Failed to decode response: zlib_decode(): data error Retrying with degraded;

    composer update的时候出现: Failed to decode response: zlib_decode(): data error Retrying with degraded: 执 ...

  2. win7旗舰版 安装IIS中出现的问题

    最好先安装IIS成功了,再安装VS2010或者别的版本 1.hppt 错误500.19,-Internal server erroe,无法访问的请求野蛮,因为该页的相关配置数据无效,HTTP Erro ...

  3. android ui篇 自己写界面

    对于一些较为简单的界面则自己进行写. 在这里就需要了解xml文件中一些基本的属性以及android手机的知识. 一.目前手机屏幕像素密度基本有5种情况.(以下像素密度简称密度) 密度 ldpi mdp ...

  4. Android Studio support 26.0.0-alpha1 Failed to resolve: com.android.support:appcompat-v7:27.+ 报错解决方法

    AS下如何生成自定义的.jks签名文件, 以及如何生成数字签名 链接:http://www.cnblogs.com/smyhvae/p/4456420.html 链接:http://blog.csdn ...

  5. RLearning第2弹:创建数据集

    任何一门语言,数据类型和数据结构是最基础,也是最重要的,必须要学好!1.产生向量 a<-c(1,2,5,3,6,-2,4) b<-c("one","two&q ...

  6. ADO.NET概述

    xml这类文件它是.net变成环境中优先使用的数据访问借口. ADO.NET传输的数据都是XML格式的 ADO.NET是一组用于和数据源惊醒交互的面向对象类库 数据源:通常是各种数据库,但文本.exc ...

  7. (转载)C#格式规范

    前言 之前工作中整理的一篇编码规范. 代码注释 注释约定 只在需要的地方加注释,不要为显而易见的代码加注释使用 /// 生成的xml标签格式的文档注释 方法注释 所有的方法都应该以描述这段代码的功能的 ...

  8. 暑假集训第一周比赛G题

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83146#problem/G G - 向 Crawling in process... C ...

  9. java深入探究01

    经过前面基础部门的学习,希望大家都把基础打闹再继续深入探究java应用层面的知识,以后的日子我会继续更新java进阶知识,深入探究实际工作中的java应用,说的不好的地方还请见谅,如果能提出你宝贵的建 ...

  10. bash rz 上传文件失败问题

    原文链接: https://blog.csdn.net/heavendai/article/details/7549065 单独用rz会有两个问题:上传中断.上传文件变化(md5不同), 解决办法是上 ...