我使用node-ffi调用EnumPrintersA / EnumPrintersW函数来获取可从我的 PC 访问的本地打印机列表。
您应该创建将由 EnumPrinters 函数填充信息的缓冲区。
但是您不知道所需的缓冲区大小。
在这种情况下,您需要执行EnumPrintersA / EnumPrintersW两次。
在第一次调用期间,此函数计算有关打印机信息的内存量,在第二次调用期间,此函数用有关打印机的信息填充缓冲区。如果是EnumPrinters
的 Unicode 版本
功能,打印机名称中的每个字母将在 Windows 中使用两个字符进行编码。
为什么第一次调用EnumPrintersW返回与第一次调用EnumPrintersA相同的所需内存量?
Unicode 字符串的长度是非 Unicode 字符串的两倍,但所需的缓冲区大小相同。
var ffi = require('ffi')
var ref = require('ref')
var Struct = require('ref-struct')
var wchar_t = require('ref-wchar')
var int = ref.types.int
var intPtr = ref.refType(ref.types.int)
var wchar_string = wchar_t.string
var getPrintersA = function getPrinters() {
var PRINTER_INFO_4A = Struct({
'pPrinterName' : ref.types.CString,
'pServerName' : ref.types.CString,
'Attributes' : int
});
var printerInfoPtr = ref.refType(PRINTER_INFO_4A);
var winspoolLib = new ffi.Library('winspool', {
'EnumPrintersA': [ int, [ int, ref.types.CString, int, printerInfoPtr, int, intPtr, intPtr ] ]
});
var pcbNeeded = ref.alloc(int, 0);
var pcReturned = ref.alloc(int, 0);
//Get amount of memory for the buffer with information about printers
var res = winspoolLib.EnumPrintersA(6, ref.NULL, 4, ref.NULL, 0, pcbNeeded, pcReturned);
if (res != 0) {
console.log("Cannot get list of printers. Error during first call to EnumPrintersA. Error: " + res);
return;
}
var bufSize = pcbNeeded.deref();
var buf = Buffer.alloc(bufSize);
console.log(bufSize);
//Fill buf with information about printers
res = winspoolLib.EnumPrintersA(6, ref.NULL, 4, buf, bufSize, pcbNeeded, pcReturned);
if (res == 0) {
console.log("Cannot get list of printers. Eror: " + res);
return;
}
var countOfPrinters = pcReturned.deref();
var printers = Array(countOfPrinters);
for (var i = 0; i < countOfPrinters; i++) {
var pPrinterInfo = ref.get(buf, i*PRINTER_INFO_4A.size, PRINTER_INFO_4A);
printers[i] = pPrinterInfo.pPrinterName;
}
return printers;
};
var getPrintersW = function getPrinters() {
var PRINTER_INFO_4W = Struct({
'pPrinterName' : wchar_string,
'pServerName' : wchar_string,
'Attributes' : int
});
var printerInfoPtr = ref.refType(PRINTER_INFO_4W);
var winspoolLib = new ffi.Library('winspool', {
'EnumPrintersW': [ int, [ int, wchar_string, int, printerInfoPtr, int, intPtr, intPtr ] ]
});
var pcbNeeded = ref.alloc(int, 0);
var pcReturned = ref.alloc(int, 0);
//Get amount of memory for the buffer with information about printers
var res = winspoolLib.EnumPrintersW(6, ref.NULL, 4, ref.NULL, 0, pcbNeeded, pcReturned);
if (res != 0) {
console.log("Cannot get list of printers. Error during first call to EnumPrintersW. Eror code: " + res);
return;
}
var bufSize = pcbNeeded.deref();
var buf = Buffer.alloc(bufSize);
console.log(bufSize);
//Fill buf with information about printers
res = winspoolLib.EnumPrintersW(6, ref.NULL, 4, buf, pcbNeeded.deref(), pcbNeeded, pcReturned);
if (res == 0) {
console.log("Cannot get list of printers. Eror code: " + res);
return;
}
var countOfPrinters = pcReturned.deref();
var printers = new Array(countOfPrinters);
for (var i = 0; i < countOfPrinters; i++) {
var pPrinterInfo = ref.get(buf, i*PRINTER_INFO_4W.size, PRINTER_INFO_4W);
printers[i] = pPrinterInfo.pPrinterName;
}
return printers;
};
https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd162692(v=vs.85).aspx
BOOL EnumPrinters(
_In_ DWORD Flags,
_In_ LPTSTR Name,
_In_ DWORD Level,
_Out_ LPBYTE pPrinterEnum,
_In_ DWORD cbBuf,
_Out_ LPDWORD pcbNeeded,
_Out_ LPDWORD pcReturned
);
https://msdn.microsoft.com/ru-ru/library/windows/desktop/dd162847(v=vs.85).aspx
typedef struct _PRINTER_INFO_4 {
LPTSTR pPrinterName;
LPTSTR pServerName;
DWORD Attributes;
} PRINTER_INFO_4, *PPRINTER_INFO_4;