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. 教你管理SQL数据库系列(1-4)

    原文 教你管理 SQL Server 数据库(1)数据库的结构  http://bbs.51cto.com/thread-1084951-1.html教你管理 SQL Server 数据库(2)系统数 ...

  2. Data Structure Binary Tree: Boundary Traversal of binary tree

    http://www.geeksforgeeks.org/boundary-traversal-of-binary-tree/ #include <iostream> #include & ...

  3. curl常用指令

    curl 发送GET请求获取标准输出 curl -I 显示http请求头 curl -i 显示请求头及输出内容 curl xxx > xxx 将输出重定向到本地文件(本地文件无需已存在,一般不写 ...

  4. vue-router原理分析

    本文整理总结自: https://zhuanlan.zhihu.com/p/27588422 单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面, 实现这一点主要是两种方式: 1.Hash: ...

  5. import from 'xxx'是如何找到node_modules目录下的

    起初我认为这是ES6或者Webpack的语法,但查阅相关API后并没有相关说明,通过进一步地搜索,才知道这是Node模块系统的约定和实现(Webpack打包工具是兼容node模块系统的,自然遵守相关规 ...

  6. F5与Ctrl+F5及地址栏输入地址回车

    按F5等同于点击页面地址栏的刷新图标. 地址栏输入地址然后回车: 根据缓存内容是否过期决定是否发送请求给服务端 F5: 浏览器无论如何都得发送请求给服务端,包含If-Modified-Since/If ...

  7. BZOJ 2058 [Usaco2010 Nov]Cow Photographs:逆序对【环上最小逆序对】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2058 题意: 给你一个由1~n组成的排列,首尾相接围成一个环. 你可以任意次交换其中两个相 ...

  8. 分享知识-快乐自己:虚拟机 NET 网络配置

    第一步: 第二步: 第三步:   第四步:   第五步: 第六步: 第七步: 第九步: 第十步: 第十一步: 第十二步:   第十三步: 成功. 第十四步:开启开机自启动网路连接 cd /etc/sy ...

  9. jQuery与javascript库

    [jquery-javascript库] 为了简化javascript的开发,诞生了javascript程序库,他封装了很多预定的对象和实用函数.下面是几种流行的javascript程序库:proto ...

  10. C#中substring ()的用法

    C#中substring ()的用法:http://www.cnblogs.com/bluespace/archive/2007/12/11/782336.html