Pull to refresh

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

Reading time4 min
Views25K
Со вчерашнего дня, господа, можно написать вот такой скрипт:

// функция преобразования строки 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
Comments33

Articles