nodejs利用windows API读取文件属性(dll)
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利用windows API读取文件属性(dll)的更多相关文章
- 利用 Windows API Code Pack 修改音乐的 ID3 信息
朋友由于抠门 SD 卡买小了,结果音乐太多放不下,又不舍得再买新卡,不得已决定重新转码,把音乐码率压低一点,牺牲点音质来换空间(用某些人的话说,反正不是搞音乐的,听不出差别)… 结果千千静听(百度音乐 ...
- Windows API学习---插入DLL和挂接API
插入DLL和挂接API 在Microsoft Windows中,每个进程都有它自己的私有地址空间.当使用指针来引用内存时,指针的值将引用你自己进程的地址空间中的一个内存地址.你的进程不能创建一个其引用 ...
- 利用windows api共享内存通讯
主要涉及CreateFile,CreateFileMapping,GetLastError,MapViewOfFile,sprintf,OpenFileMapping,CreateProcess Cr ...
- C#利用Windows API 实现关机、注销、重启等操作
using System; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; nam ...
- 【整理】c# 调用windows API(user32.dll)
User32.dll提供了很多可供调用的接口,大致如下(转自http://blog.csdn.net/zhang399401/article/details/6978803) using System ...
- 后端Nodejs利用node-xlsx模块读取excel
后端Nodejs(利用node-xlsx模块) /** * Created by zh on 16-9-14. */ var xlsx = require("node-xlsx") ...
- 【转】c# 调用windows API(user32.dll)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.R ...
- Windows API Hooking in Python
catalogue . 相关基础知识 . Deviare API Hook Overview . 使用ctypes调用Windows API . pydbg . winappdbg . dll inj ...
- Windows Dll Injection、Process Injection、API Hook、DLL后门/恶意程序入侵技术
catalogue 1. 引言2. 使用注册表注入DLL3. 使用Windows挂钩来注入DLL4. 使用远程线程来注入DLL5. 使用木马DLL来注入DLL6. 把DLL作为调试器来注入7. 使用c ...
随机推荐
- 如何判断移动终端访问还是PC访问?
我们经常需要知道访问网站的设备是移动终端还是PAD还是PC,下面给出判断的java代码供参考.实现的原理就是获取HTTP消息头里User-Agent和x-wap-profile,User-下面是Use ...
- 常见数据挖掘算法的Map-Reduce策略(1)
大数据这个名词是被炒得越来越火了,各种大数据技术层出不穷,做数据挖掘的也跟着火了一把,呵呵,现今机器学习算法常见的并行实现方式:MPI,Map-Reduce计算框架,GPU方面,grap ...
- Android SDK上手指南 2:用户界面设计
http://mobile.51cto.com/ahot-419184.htm 内容简介 我们将为应用程序项目添加布局方案,在这方面XML与Eclipse ADT接口将成为工作中的得力助手——不过在后 ...
- css 分析
.important.warning {background:silver;} .important .warning {background:silver;} //上面有什么区别? //1.2个选择 ...
- IE盒模型和标准盒模型
标准盒模型和ie盒模型(怪异盒模型) w3c标准盒模型 width和height不包括padding和border ie盒模型 width和height包含padding和border ie8以上都是 ...
- Delphi回调函数的使用-例子
Delphi回调函数的使用-例子 功能大体描述:Form1中有一个Edit和一个Button,当点击BUTTON时弹出FORM2,FORM2中也有一个EDIT和一个BUTTON,当点击FORM2中的B ...
- Entity Framework 学习笔记(二)之数据模型 Model 使用过程
Entity Framework 数据模型 Model 创建的使用: 开发环境:VS2012 数据库:SQL Server 2008 Entity Framework 版本:6.12 下面是新建的 ...
- HIVE- 新建UDF范例
首先pom文件导入依赖,Hadoop和hive的依赖导入自己机器的版本,hive记得导jdbc <dependency> <groupId>org.apache.hadoop& ...
- CDN存储和加速静态文件是什么回事(整理)(CDN是什么)
CDN存储和加速静态文件是什么回事(整理)(CDN是什么) 一.总结 一句话总结: 内容分发网络:Content Delivery Network:依靠网络中的各个节点,就近发放静态资源. CDN的全 ...
- java:Maven构建项目速度太慢的解决办法,以及报错Retrieving archetypes:' has encountered a problem
如果报错信息如下: Retrieving archetypes:' has encountered a problemAn internal error occurred during:"R ...