Pull to refresh

Вызываем функции Windows API (и любые другие функции, написанные на языке Си) джаваскриптом из Node.js

Reading time 4 min
Views 24K
Со вчерашнего дня, господа, можно написать вот такой скрипт:

// функция преобразования строки JavaScript (UTF-8) в UTF-16
function TEXT(text){
   return new Buffer(text, 'ucs2').toString('binary');
}

var FFI = require('node-ffi');

// подключаемся к user32.dll
var user32 = new FFI.Library('user32', {
   'MessageBoxW': [
      'int32', [ 'int32', 'string', 'string', 'int32' ]
   ]
});

// диалоговое окно
var OK_or_Cancel = user32.MessageBoxW(
   0, TEXT('Привет, Хабрахабр!'), TEXT('Заголовок окна'), 1
);

и, запустив его в Windows, получить желаемый результат — диалоговое окно Windows.

Это стало возможным потому, что модуль node-ffi (обёртку вокруг той необыкновенно полезной библиотеки libffi, которая используется для вызова библиотек на языке Си не менее чем в восьми других языках) вчера портировали на Windows.

Следует, разумеется, помнить о том, что в Windows API используются строки в формате UTF-16, а джаваскриптовые строки Node.js хранит в UTF-8. Воплощением этой разницы является в моём примере преобразователь TEXT() аналог одноимённого макро, описанного в MSDN.

Ясное дело, что на Windows API свет клином не сошёлся: модуль node-ffi можно использовать для вызова какой угодно библиотеки, написанной на языке Си или соблюдающей принятый в Си способ вызова функций (например, в Си++ это достигается директивою extern "C").

Что означает этот шаг эволюции возможностей Node.js?

Напомню предсказание, сделанное мною меньше месяца назад — шестнадцатого декабря 2011 года:
В настоящее время будущее Node.js ещё не достаточно лучезарно, поскольку ещё только ≈1½ месяца этот движок существует не только под Linux, под Мак и под Соляркою, но также и под Windows.

Следует ожидать мощного синергического толчка в тот момент, когда код модулей для Node.js начнут сочинять также и те разработчики на JavaScript, у которых на рабочем компьютере стоит Windows. По моим оценкам, для этого не достаточно портировать на Windows один только сам движок Node.js; потребуется также, по меньшей мере, вот что:
  • Плавная работа пакетного менеджера npm. В частности, будет необыкновенном полезным появление у разработчиков модулей возможности поставлять заранее скомпилированные модули для win32 и win64: нельзя же полагаться на то, что у каждого конечного пользователя стоят средства разработки (например, Visual Studio 2010 Express). Понятно, что и разработчики модулей должны взяться за ум, а не то даже команду npm install zip нельзя под Windows подать без того, чтобы наткнуться на симлинк внутри тарболла. (Или автор скрипта npm/lib/utils/tar.js мог бы получше предусмотреть это.)
      
  • Появление возможности оскриптовывания произвольной системной библиотеки. (Появится, вероятно, после портирования node-ffi на Windows.) Только отсюда протянется тропка к сотворению GUI.
      
  • Появление возможности работать с БД файлового (а не клиент-серверного) типа. (Появится, вероятно, после портирования node-sqlite3 на Windows.)
И месяца не прошло, как второй из этих трёх пунктов реализовался. Любая библиотека может быть оскриптована джаваскриптами. Соответственно, приложениям на Node.js под Windows стала доступна вся мощь системных API, а кросс-платформенные приложения могут невозбранно обращаться ко кросс-платформенным библиотекам, таская их с собою.

Первый из этих трёх пунктов (касавшийся как раз таскания библиотек с собою) не реализовался в том виде, в каком я мечтал о нём: пакетный менеджер npm всё ещё не обеспечивает возможность доставки только того скомпилированного кода, который нужен конкретной системе. Но у меня появился новый повод для оптимизма после того, как я увидел, что разработчикам модуля node-ffi удалось обойти нехватку такой возможности. Их модуль содержит один и тот же код, скомпилированный под полдесятка различных платформ:
compiled/darwin/x64/ffi_bindings.node
compiled/linux/ia32/ffi_bindings.node
compiled/linux/x64/ffi_bindings.node
compiled/sunos/ia32/ffi_bindings.node
compiled/win32/ia32/ffi_bindings.node
а скрипт lib/bindings.js во время вызова модуля node-ffi оглядывается, соображая, куда же попал он, и подбирает нужный двоичный код:

var join = require('path').join
  , bindings = 'ffi_bindings.node'

function requireTry () {

  var i = 0
    , l = arguments.length
    , n

  for (; i<l; i++) {
    n = arguments[i]
    try {
      var b = require(n)
      b.path = n
      return b
    } catch (e) {
      if (!/not find/i.test(e.message)) {
        throw e
      }
    }
  }

  throw new Error('Could not load the bindings file. Tried:\n' +
      [].slice.call(arguments).map(function (a) { return '  - ' + a }).join('\n'))
}

module.exports = requireTry(
    // Production "Release" buildtype binary
    join(__dirname, '..', 'compiled', process.platform, process.arch, bindings)
    // Release files, but manually compiled
  , join(__dirname, '..', 'out', 'Release', bindings) // Unix
  , join(__dirname, '..', 'Release', bindings)        // Windows
    // Debug files, for development
  , join(__dirname, '..', 'out', 'Debug', bindings)   // Unix
  , join(__dirname, '..', 'Debug', bindings)          // Windows
)

Как видно, работает ничуть не хуже; папка «compiled» вот только занимает ≈700 килобайтов, но при нынешних объёмах дисков и скоростях сетей об этом можно позабыть.

Итак, остаётся дождаться доступа к SQLite — и Node.js под Windows станет платформою, пригодною для разработки на JavaScript множества фактически полезных приложений. Но с учётом вышесказанного можно считать, что кросс-платформенная разработка модулей-обёрток упростилася; стало быть, нам недолго осталось ждать и обёртку вокруг SQLite, и появления модулей для интеграции Node.js с целым рядом других известных кросс-платформенных библиотек.
Tags:
Hubs:
+37
Comments 33
Comments Comments 33

Articles