找到一点资料,关于win32 api调用的,Nodejs相关应用探讨(自己的笔记),记录在这里
找到一点资料,关于win32 api调用的,Nodejs相关应用探讨(自己的笔记),记录在这里
http://www.reddit.com/r/javascript/comments/103fkg/64bit_nodejs_winforms/
var ffi = require('ffi'),
ref = require('ref'),
Struct = require('ref-struct'),
hWnd = new Buffer(8);
var ICCx = Struct({
'dwSize': 'int32',
'dwICC': 'int32'
});
var ICCxPtr = ref.refType(ICCx);
var comctl32 = ffi.Library('comctl32', {
'InitCommonControlsEx': ['int32', [ICCxPtr]]
});
var WndClassEx = Struct({
'cbSize': 'uint32',
'style': 'uint32',
'lpfnWndProc': 'pointer', // callback 'int32', ['pointer', 'uint32', 'int32', 'uint32']
'cbClsExtra': 'int32',
'cbWndExtra': 'int32',
'hInstance': 'pointer', // can be 0?
'hIcon': 'pointer',
'hCursor': 'pointer',
'hbrBackground': 'pointer',
'lpszMenuName': 'pointer',
'lpszClassName': 'pointer',
'hIconSm': 'pointer'
});
var WndClassExPtr = ref.refType(WndClassEx);
var user32 = ffi.Library('user32', {
'RegisterClassExW': ['int32', [WndClassExPtr]],
'CreateWindowExW': ['pointer', [
'int32', 'pointer', 'pointer', 'int32', // style, name, name, style
'int32', 'int32', 'int32', 'int32', // x, y, w, h
'pointer', 'pointer', 'pointer', 'pointer' // handles
]],
'DefWindowProcW': ['uint32', ['pointer', 'uint32', 'int32', 'pointer']],
'ShowWindow': ['bool', ['pointer', 'int32']],
'UpdateWindow': ['bool', ['pointer']],
'GetMessageW': ['bool', ['pointer', 'pointer', 'uint32', 'uint32']],
'TranslateMessageEx': ['bool', ['pointer']],
'DispatchMessageW': ['uint32', ['pointer']]
});
var kernel32 = ffi.Library('kernel32', {
'GetModuleHandleExW': ['bool', [
'int32', 'pointer', 'pointer' // flags, optional LPCTSTR name, ref hModule
]], // etc... / kernel32 is your friend!
});
var Msg = Struct({
'hwnd': 'pointer',
'message': 'uint32',
'wParam': 'int32',
'lParam': 'pointer',
'time': 'int32',
'pX': 'int32',
'pY': 'int32'
});
// App-specific
// Names
var className = new Buffer('Node.js WinForms Class\0', 'ucs-2');
var windowName = new Buffer('Node.js WinForms App\0', 'ucs-2');
// hInstance
var hInstance = new Buffer(8);
kernel32.GetModuleHandleExW(0, null, hInstance);
// WndProc
var WndProc = ffi.Callback('uint32',
['pointer', 'uint32', 'int32', 'pointer'],
function(hwnd, uMsg, wParam, lParam) {
console.log('Got Message: ' + uMsg + ' /', hwnd.deref());
var result = 0; // ref.alloc('int32');
switch(uMsg) {
default:
result = user32.DefWindowProcW(hwnd, uMsg, wParam, lParam);
console.log('DefWindowProc LRESULT: ' + result);
return result;
}
console.log('Sending LRESULT: ' + result.deref())
return result;
}
);
// Common Controls
var icc = new ICCx;
icc.dwSize = 8;
icc.dwICC = 0x40ff;
comctl32.InitCommonControlsEx(icc.ref());
// Window Class
var wClass = new WndClassEx;
wClass.cbSize = 80; // x86 = 48
wClass.style = 0;
wClass.lpfnWndProc = WndProc;
wClass.cbClsExtra = 0;
wClass.cbWndExtra = 0;
wClass.hInstance = hInstance;
wClass.hIcon = null;
wClass.hCursor = null;
wClass.hbrBackground = null;
wClass.lpszMenuName = null;
wClass.lpszClassName = className;
wClass.hIconSm = null;
if (!user32.RegisterClassExW(wClass.ref()))
throw 'Error registering class';
hWnd = user32.CreateWindowExW(
0,
className,
windowName,
0xcf0000, // overlapped window
1 << 31, // use default
1 << 31,
320,
200,
null, null, hInstance, null
);
console.log(hWnd);
user32.ShowWindow(hWnd, 1);
user32.UpdateWindow(hWnd);
// message loop
var msg = new Msg;
var getMsgRes = 0;
while (user32.GetMessageW(msg.ref(), null, 0, 0)) {
user32.TranslateMessageEx(msg.ref());
user32.DispatchMessageW(msg.ref());
}
return msg.wParam;
以下是一个关于如何在 Node.js 中使用 ffi
和 ref
库来调用 Windows API 的示例。该示例展示了如何创建一个基本的窗口应用程序。
示例代码
const ffi = require('ffi');
const ref = require('ref');
const Struct = require('ref-struct');
const path = require('path');
// 定义结构体
const POINT = Struct({
x: 'int32',
y: 'int32'
});
const MSG = Struct({
hwnd: 'pointer',
message: 'uint32',
wParam: 'int32',
lParam: 'pointer',
time: 'int32',
pt: POINT
});
const WNDCLASSEX = Struct({
cbSize: 'uint32',
style: 'uint32',
lpfnWndProc: 'pointer',
cbClsExtra: 'int32',
cbWndExtra: 'int32',
hInstance: 'pointer',
hIcon: 'pointer',
hCursor: 'pointer',
hbrBackground: 'pointer',
lpszMenuName: 'pointer',
lpszClassName: 'pointer',
hIconSm: 'pointer'
});
// 加载库
const user32 = ffi.Library('user32', {
'RegisterClassExW': ['uint32', ['pointer']],
'CreateWindowExW': ['pointer', ['uint32', 'string', 'string', 'uint32', 'int32', 'int32', 'int32', 'int32', 'pointer', 'pointer', 'pointer', 'pointer']],
'DefWindowProcW': ['uint32', ['pointer', 'uint32', 'int32', 'pointer']],
'ShowWindow': ['bool', ['pointer', 'int32']],
'UpdateWindow': ['bool', ['pointer']],
'GetMessageW': ['bool', ['pointer', 'pointer', 'uint32', 'uint32']],
'TranslateMessage': ['bool', ['pointer']],
'DispatchMessageW': ['uint32', ['pointer']]
});
const kernel32 = ffi.Library('kernel32', {
'GetModuleHandleW': ['pointer', ['pointer']]
});
// 窗口过程函数
const WndProc = ffi.Callback('uint32', ['pointer', 'uint32', 'int32', 'pointer'], (hwnd, msg, wParam, lParam) => {
if (msg === 0x0010 /* WM_DESTROY */) { // WM_DESTROY 消息
user32.PostQuitMessage(0);
} else {
return user32.DefWindowProcW(hwnd, msg, wParam, lParam);
}
return 0;
});
// 注册窗口类
const wc = new WNDCLASSEX();
wc.cbSize = wc.size;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = kernel32.GetModuleHandleW(null);
wc.hIcon = null;
wc.hCursor = null;
wc.hbrBackground = null;
wc.lpszMenuName = null;
wc.lpszClassName = 'NodeJSWindow';
wc.hIconSm = null;
if (user32.RegisterClassExW(wc.ref()) === 0) {
throw new Error('Failed to register window class');
}
// 创建窗口
const hWnd = user32.CreateWindowExW(
0, // dwExStyle
wc.lpszClassName, // lpClassName
'Node.js Window', // lpWindowName
0x80000000 | 0x40000000, // dwStyle
100, // X
100, // Y
800, // nWidth
600, // nHeight
null, // hWndParent
null, // hMenu
wc.hInstance, // hInstance
null // lpParam
);
if (!hWnd) {
throw new Error('Failed to create window');
}
// 显示并更新窗口
user32.ShowWindow(hWnd, 5); // SW_SHOW
user32.UpdateWindow(hWnd);
// 消息循环
const msg = new MSG();
while (user32.GetMessageW(msg.ref(), null, 0, 0) !== 0) {
user32.TranslateMessage(msg.ref());
user32.DispatchMessageW(msg.ref());
}
解释
-
结构体定义:
POINT
结构体用于表示点。MSG
结构体用于表示消息。WNDCLASSEX
结构体用于表示窗口类。
-
加载库:
- 使用
ffi.Library
加载user32.dll
和kernel32.dll
,以便调用相应的 Windows API 函数。
- 使用
-
窗口过程函数:
WndProc
是窗口过程函数,用于处理窗口消息。这里处理了WM_DESTROY
消息,并调用PostQuitMessage
退出消息循环。
-
注册窗口类:
- 创建一个
WNDCLASSEX
实例并填充其字段,然后使用RegisterClassExW
注册窗口类。
- 创建一个
-
创建窗口:
- 使用
CreateWindowExW
创建窗口。
- 使用
-
显示和更新窗口:
- 使用
ShowWindow
和UpdateWindow
显示并更新窗口。
- 使用
-
消息循环:
- 使用
GetMessageW
、TranslateMessage
和DispatchMessageW
进行消息循环。
- 使用
以上代码展示了如何使用 Node.js 调用 Windows API 创建一个简单的窗口应用程序。
MARK
这段代码展示了如何使用Node.js调用Windows API来创建一个简单的窗口应用程序。以下是一些关键点的解释:
-
引入必要的库:
var ffi = require('ffi'), ref = require('ref'), Struct = require('ref-struct');
这里引入了
ffi
、ref
和ref-struct
库,分别用于加载动态链接库、处理C风格的数据类型以及定义结构体。 -
定义数据结构:
var ICCx = Struct({ 'dwSize': 'int32', 'dwICC': 'int32' });
定义了一个名为
ICCx
的结构体,它包含两个整型成员。 -
加载Windows API库:
var comctl32 = ffi.Library('comctl32', { 'InitCommonControlsEx': ['int32', [ICCxPtr]] });
加载
comctl32.dll
库,并导出其中的InitCommonControlsEx
函数。 -
定义窗口类:
var WndClassEx = Struct({ 'cbSize': 'uint32', 'style': 'uint32', 'lpfnWndProc': 'pointer', 'cbClsExtra': 'int32', 'cbWndExtra': 'int32', 'hInstance': 'pointer', 'hIcon': 'pointer', 'hCursor': 'pointer', 'hbrBackground': 'pointer', 'lpszMenuName': 'pointer', 'lpszClassName': 'pointer', 'hIconSm': 'pointer' });
定义了一个窗口类结构体
WndClassEx
,包含了窗口类的所有属性。 -
注册窗口类:
if (!user32.RegisterClassExW(wClass.ref())) throw 'Error registering class';
使用
RegisterClassExW
函数注册窗口类。 -
创建窗口:
hWnd = user32.CreateWindowExW( 0, className, windowName, 0xcf0000, 1 << 31, 1 << 31, 320, 200, null, null, hInstance, null );
使用
CreateWindowExW
函数创建窗口。 -
消息循环:
while (user32.GetMessageW(msg.ref(), null, 0, 0)) { user32.TranslateMessageEx(msg.ref()); user32.DispatchMessageW(msg.ref()); }
创建一个消息循环来处理用户输入和其他事件。
这段代码演示了如何通过Node.js调用Windows API来创建一个简单的窗口应用程序。