npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

windows-shortcut-ffi

v1.0.0

Published

Create and query Windows .lnk shortcuts from Node.js through node:ffi. No C++, no native addon, no child process.

Readme

windows-shortcut-ffi

English | 简体中文

在 Windows 上创建 / 读取 .lnk 快捷方式。功能对标 windows-shortcut-napi, 但不使用任何 C++ / Node-API 原生插件,全部通过 Node.js 内置的 node:ffi 直接调用 Win32 与 COM。

  • 纯 JavaScript(CommonJS),零第三方依赖
  • 路径、参数、描述以 UTF-16 直接传给 Windows Shell Link API,不受控制台 ANSI 代码页限制,中文/日文等路径不会乱码
  • 自带 TypeScript 声明

前置条件

  • 仅 Windows。
  • Node.js 构建需带 node:ffi,并且运行时要显式开启实验开关:
set NODE_OPTIONS=--experimental-ffi
node your-app.js
# PowerShell
$env:NODE_OPTIONS = "--experimental-ffi"
node your-app.js

node:ffi 是实验特性,启动时会打印 ExperimentalWarning: FFI is an experimental feature, 可用 --no-warnings 抑制,或在 NODE_OPTIONS 里一起加上。若未开启开关,本库在 require 时会给出明确报错而不是莫名其妙地失败。

安装

npm install windows-shortcut-ffi

用法

const shortcut = require('windows-shortcut-ffi');

// 基础用法
shortcut.create('C:/Users/YourName/Desktop/Notepad.lnk', 'C:/Windows/System32/notepad.exe');

// 完整选项
shortcut.create('C:/Users/YourName/Desktop/Notepad.lnk', {
  target: 'C:/Windows/System32/notepad.exe',
  args: 'C:/temp/示例.txt',
  workingDir: 'C:/temp',
  runStyle: shortcut.SW_SHOWNORMAL,
  icon: 'C:/Windows/System32/shell32.dll',
  iconIndex: 0,
  hotkey: 0,
  desc: '用记事本打开示例.txt',
});

// 读取
const info = shortcut.query('C:/Users/YourName/Desktop/Notepad.lnk');
// { target, args, workingDir, icon, iconIndex, hotkey, runStyle }

TypeScript:

import * as shortcut from 'windows-shortcut-ffi';

shortcut.create('C:/temp/App.lnk', {
  target: 'C:/Program Files/My App/app.exe',
  args: '--profile default',
  runStyle: shortcut.SW_SHOWMAXIMIZED,
});

API

create(path, target)

创建指向 target 的快捷方式。

create(path, options)

| 字段 | 类型 | 说明 | | --- | --- | --- | | target | string | 目标文件或可执行程序路径(必填) | | args | string \| null | 命令行参数 | | workingDir | string \| null | 工作目录 | | runStyle | number \| null | 窗口显示方式 | | icon | string \| null | 图标来源路径 | | iconIndex | number \| null | 图标资源索引 | | hotkey | number \| null | 快捷键,直接透传给 Shell Link API | | desc | string \| null | 快捷方式描述 |

query(path)

返回 { target, args, workingDir, icon, iconIndex, hotkey, runStyle }。

常量

  • SW_SHOWNORMAL
  • SW_SHOWMAXIMIZED
  • SW_SHOWMINNOACTIVE

错误

参数非法抛 TypeError;原生调用失败抛 ShortcutError:

try {
  shortcut.create('C:/invalid/path/test.lnk', { target: 'C:/missing/file.exe' });
} catch (error) {
  if (error instanceof shortcut.ShortcutError) {
    console.error(error.message); // 含 HRESULT
    console.error('reason:', error.reason); // 例如 "ERROR_PATH_NOT_FOUND: The system cannot find the path specified."
    console.error('status:', error.status); // 内部阶段码
    console.error('hr:', error.hr);         // 无符号 32 位 HRESULT
  }
}

实现原理

COM 接口在内存中的形态是:对象首字段是虚表指针,虚表里是函数指针数组。C 里 p->lpVtbl->SetPath(p, path) 就是「读虚表第 N 项,按地址调用」。

node:ffi 只能按符号名解析函数(library.getFunction(name, sig),内部走 GetProcAddress), 没有把运行时读出来的地址变成可调用 JS 函数的入口,所以无法直接跳转调用虚表里的函数指针, 也不允许为此写 C++ 跳板。

因此本库用 oleaut32!DispCallFunc 作为通用虚表调用器 —— 它接收「对象指针 + 虚表字节偏移 + 参数 VARIANT 数组」, 内部完成的就是上面那条调用链,语义等价于 C 的直接调用,只是这段跳板由系统 DLL 提供:

HRESULT DispCallFunc(void* pvInstance, ULONG_PTR oVft, CALLCONV cc,
                     VARTYPE vtReturn, UINT cActuals, VARTYPE* prgvt,
                     VARIANTARG** prgpvarg, VARIANT* pvargResult);

其余部分:

  • ole32.dll:CoInitializeEx / CoUninitialize / CoCreateInstance
  • IShellLinkW、IPersistFile 的虚表槽位在 lib/vtable.js 中声明(对照 Windows SDK 头文件核实)
  • 原生内存用 Buffer + ffi.getRawPointer(),由 GC 管理,无需手动释放也不会泄漏
  • 字符串用 ffi.exportString(str, ptr, len, 'utf16le') 写入,即 NUL 结尾的 UTF-16LE

测试

npm test        # node --experimental-ffi test/smoke.js
npm run probe   # 只验证 DispCallFunc 这一条调用通路是否可用
npm run example # 在当前目录创建 Notepad.lnk

许可

ISC