@luckykiet/node-printer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,750 @@
1
+ #include "node_printer.hpp"
2
+
3
+ #if _MSC_VER
4
+ #include <windows.h>
5
+ #include <Winspool.h>
6
+ #include <Wingdi.h>
7
+ #pragma comment(lib, "Winspool.lib")
8
+ #else
9
+ #error "Unsupported compiler for windows. Feel free to add it."
10
+ #endif
11
+
12
+ #include <string>
13
+ #include <map>
14
+ #include <utility>
15
+ #include <sstream>
16
+ #include <node_version.h>
17
+
18
+ namespace{
19
+ typedef std::map<std::string, DWORD> StatusMapType;
20
+
21
+ /** Memory value class management to avoid memory leak
22
+ */
23
+ template<typename Type>
24
+ class MemValue: public MemValueBase<Type> {
25
+ public:
26
+ /** Constructor of allocating iSizeKbytes bytes memory;
27
+ * @param iSizeKbytes size in bytes of required allocating memory
28
+ */
29
+ MemValue(const DWORD iSizeKbytes) {
30
+ _value = (Type*)malloc(iSizeKbytes);
31
+ }
32
+
33
+ ~MemValue () {
34
+ free();
35
+ }
36
+ protected:
37
+ virtual void free() {
38
+ if(_value != NULL)
39
+ {
40
+ ::free(_value);
41
+ _value = NULL;
42
+ }
43
+ }
44
+ };
45
+
46
+ struct PrinterHandle
47
+ {
48
+ PrinterHandle(LPWSTR iPrinterName)
49
+ {
50
+ _ok = OpenPrinterW(iPrinterName, &_printer, NULL);
51
+ }
52
+ ~PrinterHandle()
53
+ {
54
+ if(_ok)
55
+ {
56
+ ClosePrinter(_printer);
57
+ }
58
+ }
59
+ operator HANDLE() {return _printer;}
60
+ operator bool() { return (!!_ok);}
61
+ HANDLE & operator *() { return _printer;}
62
+ HANDLE * operator ->() { return &_printer;}
63
+ const HANDLE & operator ->() const { return _printer;}
64
+ HANDLE _printer;
65
+ BOOL _ok;
66
+ };
67
+
68
+ const StatusMapType& getStatusMap()
69
+ {
70
+ static StatusMapType result;
71
+ if(!result.empty())
72
+ {
73
+ return result;
74
+ }
75
+ // add only first time
76
+ #define STATUS_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
77
+ STATUS_PRINTER_ADD("BUSY", PRINTER_STATUS_BUSY);
78
+ STATUS_PRINTER_ADD("DOOR-OPEN", PRINTER_STATUS_DOOR_OPEN);
79
+ STATUS_PRINTER_ADD("ERROR", PRINTER_STATUS_ERROR);
80
+ STATUS_PRINTER_ADD("INITIALIZING", PRINTER_STATUS_INITIALIZING);
81
+ STATUS_PRINTER_ADD("IO-ACTIVE", PRINTER_STATUS_IO_ACTIVE);
82
+ STATUS_PRINTER_ADD("MANUAL-FEED", PRINTER_STATUS_MANUAL_FEED);
83
+ STATUS_PRINTER_ADD("NO-TONER", PRINTER_STATUS_NO_TONER);
84
+ STATUS_PRINTER_ADD("NOT-AVAILABLE", PRINTER_STATUS_NOT_AVAILABLE);
85
+ STATUS_PRINTER_ADD("OFFLINE", PRINTER_STATUS_OFFLINE);
86
+ STATUS_PRINTER_ADD("OUT-OF-MEMORY", PRINTER_STATUS_OUT_OF_MEMORY);
87
+ STATUS_PRINTER_ADD("OUTPUT-BIN-FULL", PRINTER_STATUS_OUTPUT_BIN_FULL);
88
+ STATUS_PRINTER_ADD("PAGE-PUNT", PRINTER_STATUS_PAGE_PUNT);
89
+ STATUS_PRINTER_ADD("PAPER-JAM", PRINTER_STATUS_PAPER_JAM);
90
+ STATUS_PRINTER_ADD("PAPER-OUT", PRINTER_STATUS_PAPER_OUT);
91
+ STATUS_PRINTER_ADD("PAPER-PROBLEM", PRINTER_STATUS_PAPER_PROBLEM);
92
+ STATUS_PRINTER_ADD("PAUSED", PRINTER_STATUS_PAUSED);
93
+ STATUS_PRINTER_ADD("PENDING-DELETION", PRINTER_STATUS_PENDING_DELETION);
94
+ STATUS_PRINTER_ADD("POWER-SAVE", PRINTER_STATUS_POWER_SAVE);
95
+ STATUS_PRINTER_ADD("PRINTING", PRINTER_STATUS_PRINTING);
96
+ STATUS_PRINTER_ADD("PROCESSING", PRINTER_STATUS_PROCESSING);
97
+ STATUS_PRINTER_ADD("SERVER-UNKNOWN", PRINTER_STATUS_SERVER_UNKNOWN);
98
+ STATUS_PRINTER_ADD("TONER-LOW", PRINTER_STATUS_TONER_LOW);
99
+ STATUS_PRINTER_ADD("USER-INTERVENTION", PRINTER_STATUS_USER_INTERVENTION);
100
+ STATUS_PRINTER_ADD("WAITING", PRINTER_STATUS_WAITING);
101
+ STATUS_PRINTER_ADD("WARMING-UP", PRINTER_STATUS_WARMING_UP);
102
+ #undef STATUS_PRINTER_ADD
103
+ return result;
104
+ }
105
+
106
+ const StatusMapType& getJobStatusMap()
107
+ {
108
+ static StatusMapType result;
109
+ if(!result.empty())
110
+ {
111
+ return result;
112
+ }
113
+ // add only first time
114
+ #define STATUS_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
115
+ // Common statuses
116
+ STATUS_PRINTER_ADD("PRINTING", JOB_STATUS_PRINTING);
117
+ STATUS_PRINTER_ADD("PRINTED", JOB_STATUS_PRINTED);
118
+ STATUS_PRINTER_ADD("PAUSED", JOB_STATUS_PAUSED);
119
+
120
+ // Specific statuses
121
+ STATUS_PRINTER_ADD("BLOCKED-DEVQ", JOB_STATUS_BLOCKED_DEVQ);
122
+ STATUS_PRINTER_ADD("DELETED", JOB_STATUS_DELETED);
123
+ STATUS_PRINTER_ADD("DELETING", JOB_STATUS_DELETING);
124
+ STATUS_PRINTER_ADD("ERROR", JOB_STATUS_ERROR);
125
+ STATUS_PRINTER_ADD("OFFLINE", JOB_STATUS_OFFLINE);
126
+ STATUS_PRINTER_ADD("PAPEROUT", JOB_STATUS_PAPEROUT);
127
+ STATUS_PRINTER_ADD("RESTART", JOB_STATUS_RESTART);
128
+ STATUS_PRINTER_ADD("SPOOLING", JOB_STATUS_SPOOLING);
129
+ STATUS_PRINTER_ADD("USER-INTERVENTION", JOB_STATUS_USER_INTERVENTION);
130
+ // XP and later
131
+ #ifdef JOB_STATUS_COMPLETE
132
+ STATUS_PRINTER_ADD("COMPLETE", JOB_STATUS_COMPLETE);
133
+ #endif
134
+ #ifdef JOB_STATUS_RETAINED
135
+ STATUS_PRINTER_ADD("RETAINED", JOB_STATUS_RETAINED);
136
+ #endif
137
+
138
+ #undef STATUS_PRINTER_ADD
139
+ return result;
140
+ }
141
+
142
+ const StatusMapType& getAttributeMap()
143
+ {
144
+ static StatusMapType result;
145
+ if(!result.empty())
146
+ {
147
+ return result;
148
+ }
149
+ // add only first time
150
+ #define ATTRIBUTE_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
151
+ ATTRIBUTE_PRINTER_ADD("DIRECT", PRINTER_ATTRIBUTE_DIRECT);
152
+ ATTRIBUTE_PRINTER_ADD("DO-COMPLETE-FIRST", PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST);
153
+ ATTRIBUTE_PRINTER_ADD("ENABLE-DEVQ", PRINTER_ATTRIBUTE_ENABLE_DEVQ);
154
+ ATTRIBUTE_PRINTER_ADD("HIDDEN", PRINTER_ATTRIBUTE_HIDDEN);
155
+ ATTRIBUTE_PRINTER_ADD("KEEPPRINTEDJOBS", PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS);
156
+ ATTRIBUTE_PRINTER_ADD("LOCAL", PRINTER_ATTRIBUTE_LOCAL);
157
+ ATTRIBUTE_PRINTER_ADD("NETWORK", PRINTER_ATTRIBUTE_NETWORK);
158
+ ATTRIBUTE_PRINTER_ADD("PUBLISHED", PRINTER_ATTRIBUTE_PUBLISHED);
159
+ ATTRIBUTE_PRINTER_ADD("QUEUED", PRINTER_ATTRIBUTE_QUEUED);
160
+ ATTRIBUTE_PRINTER_ADD("RAW-ONLY", PRINTER_ATTRIBUTE_RAW_ONLY);
161
+ ATTRIBUTE_PRINTER_ADD("SHARED", PRINTER_ATTRIBUTE_SHARED);
162
+ ATTRIBUTE_PRINTER_ADD("OFFLINE", PRINTER_ATTRIBUTE_WORK_OFFLINE);
163
+ // XP
164
+ #ifdef PRINTER_ATTRIBUTE_FAX
165
+ ATTRIBUTE_PRINTER_ADD("FAX", PRINTER_ATTRIBUTE_FAX);
166
+ #endif
167
+ // vista
168
+ #ifdef PRINTER_ATTRIBUTE_FRIENDLY_NAME
169
+ ATTRIBUTE_PRINTER_ADD("FRIENDLY-NAME", PRINTER_ATTRIBUTE_FRIENDLY_NAME);
170
+ ATTRIBUTE_PRINTER_ADD("MACHINE", PRINTER_ATTRIBUTE_MACHINE);
171
+ ATTRIBUTE_PRINTER_ADD("PUSHED-USER", PRINTER_ATTRIBUTE_PUSHED_USER);
172
+ ATTRIBUTE_PRINTER_ADD("PUSHED-MACHINE", PRINTER_ATTRIBUTE_PUSHED_MACHINE);
173
+ #endif
174
+ // server 2003
175
+ #ifdef PRINTER_ATTRIBUTE_TS
176
+ ATTRIBUTE_PRINTER_ADD("TS", PRINTER_ATTRIBUTE_TS);
177
+ #endif
178
+ #undef ATTRIBUTE_PRINTER_ADD
179
+ return result;
180
+ }
181
+
182
+ const StatusMapType& getJobCommandMap()
183
+ {
184
+ static StatusMapType result;
185
+ if(!result.empty())
186
+ {
187
+ return result;
188
+ }
189
+ // add only first time
190
+ #define COMMAND_JOB_ADD(value, type) result.insert(std::make_pair(value, type))
191
+ COMMAND_JOB_ADD("CANCEL", JOB_CONTROL_CANCEL);
192
+ COMMAND_JOB_ADD("PAUSE", JOB_CONTROL_PAUSE);
193
+ COMMAND_JOB_ADD("RESTART", JOB_CONTROL_RESTART);
194
+ COMMAND_JOB_ADD("RESUME", JOB_CONTROL_RESUME);
195
+ COMMAND_JOB_ADD("DELETE", JOB_CONTROL_DELETE);
196
+ COMMAND_JOB_ADD("SENT-TO-PRINTER", JOB_CONTROL_SENT_TO_PRINTER);
197
+ COMMAND_JOB_ADD("LAST-PAGE-EJECTED", JOB_CONTROL_LAST_PAGE_EJECTED);
198
+ #ifdef JOB_CONTROL_RETAIN
199
+ COMMAND_JOB_ADD("RETAIN", JOB_CONTROL_RETAIN);
200
+ #endif
201
+ #ifdef JOB_CONTROL_RELEASE
202
+ COMMAND_JOB_ADD("RELEASE", JOB_CONTROL_RELEASE);
203
+ #endif
204
+ #undef COMMAND_JOB_ADD
205
+ return result;
206
+ }
207
+
208
+ void parseJobObject(JOB_INFO_2W *job, v8::Local<v8::Object> result_printer_job)
209
+ {
210
+ MY_NODE_MODULE_ISOLATE_DECL
211
+ //Common fields
212
+ //DWORD JobId;
213
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("id"), V8_VALUE_NEW(Number, job->JobId));
214
+ #define ADD_V8_STRING_PROPERTY(name, key) if((job->##key != NULL) && (*job->##key != L'\0')) \
215
+ { \
216
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8(#name), V8_STRING_NEW_2BYTES((uint16_t*)job->##key)); \
217
+ }
218
+ //LPTSTR pPrinterName;
219
+ ADD_V8_STRING_PROPERTY(name, pPrinterName)
220
+ //LPTSTR pPrinterName;
221
+ ADD_V8_STRING_PROPERTY(printerName, pPrinterName);
222
+ //LPTSTR pUserName;
223
+ ADD_V8_STRING_PROPERTY(user, pUserName);
224
+ //LPTSTR pDatatype;
225
+ ADD_V8_STRING_PROPERTY(format, pDatatype);
226
+ //DWORD Priority;
227
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("priority"), V8_VALUE_NEW(Number, job->Priority));
228
+ //DWORD Size;
229
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("size"), V8_VALUE_NEW(Number, job->Size));
230
+ //DWORD Status;
231
+ v8::Local<v8::Array> result_printer_job_status = V8_VALUE_NEW_DEFAULT(Array);
232
+ int i_status = 0;
233
+ for(StatusMapType::const_iterator itStatus = getJobStatusMap().begin(); itStatus != getJobStatusMap().end(); ++itStatus)
234
+ {
235
+ if(job->Status & itStatus->second)
236
+ {
237
+ Nan::Set(result_printer_job_status, i_status++, V8_STRING_NEW_UTF8(itStatus->first.c_str()));
238
+ }
239
+ }
240
+ //LPTSTR pStatus;
241
+ if((job->pStatus != NULL) && (*job->pStatus != L'\0'))
242
+ {
243
+ Nan::Set(result_printer_job_status, i_status++, V8_STRING_NEW_2BYTES((uint16_t*)job->pStatus));
244
+ }
245
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("status"), result_printer_job_status);
246
+
247
+ // Specific fields
248
+ //LPTSTR pMachineName;
249
+ ADD_V8_STRING_PROPERTY(machineName, pMachineName);
250
+ //LPTSTR pDocument;
251
+ ADD_V8_STRING_PROPERTY(document, pDocument);
252
+ //LPTSTR pNotifyName;
253
+ ADD_V8_STRING_PROPERTY(notifyName, pNotifyName);
254
+ //LPTSTR pPrintProcessor;
255
+ ADD_V8_STRING_PROPERTY(printProcessor, pPrintProcessor);
256
+ //LPTSTR pParameters;
257
+ ADD_V8_STRING_PROPERTY(parameters, pParameters);
258
+ //LPTSTR pDriverName;
259
+ ADD_V8_STRING_PROPERTY(driverName, pDriverName);
260
+ #undef ADD_V8_STRING_PROPERTY
261
+ //LPDEVMODE pDevMode;
262
+ //PSECURITY_DESCRIPTOR pSecurityDescriptor;
263
+ //DWORD Position;
264
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("position"), V8_VALUE_NEW(Number, job->Position));
265
+ //DWORD StartTime;
266
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("startTime"), V8_VALUE_NEW(Number, job->StartTime));
267
+ //DWORD UntilTime;
268
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("untilTime"), V8_VALUE_NEW(Number, job->UntilTime));
269
+ //DWORD TotalPages;
270
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("totalPages"), V8_VALUE_NEW(Number, job->TotalPages));
271
+ //SYSTEMTIME Submitted;
272
+ //DWORD Time;
273
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("time"), V8_VALUE_NEW(Number, job->Time));
274
+ //DWORD PagesPrinted;
275
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("pagesPrinted"), V8_VALUE_NEW(Number, job->PagesPrinted));
276
+ }
277
+
278
+ /**
279
+ * Returns last error code and message string
280
+ */
281
+ std::string getLastErrorCodeAndMessage() {
282
+ std::ostringstream s;
283
+ DWORD erroCode = GetLastError();
284
+ s << "code: " << erroCode;
285
+ DWORD retSize;
286
+ LPTSTR pTemp = NULL;
287
+ retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
288
+ FORMAT_MESSAGE_FROM_SYSTEM|
289
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
290
+ NULL,
291
+ erroCode,
292
+ LANG_NEUTRAL,
293
+ (LPTSTR)&pTemp,
294
+ 0,
295
+ NULL );
296
+ if (retSize && pTemp != NULL) {
297
+ //pTemp[strlen(pTemp)-2]='\0'; //remove cr and newline character
298
+ //TODO: check if it is needed to convert c string to std::string
299
+ std::string stringMessage(pTemp);
300
+ s << ", message: " << stringMessage;
301
+ LocalFree((HLOCAL)pTemp);
302
+ }
303
+
304
+ return s.str();
305
+ }
306
+
307
+ std::string retrieveAndParseJobs(const LPWSTR iPrinterName,
308
+ const DWORD& iTotalJobs,
309
+ v8::Local<v8::Object> result_printer_jobs,
310
+ PrinterHandle& iPrinterHandle)
311
+ {
312
+ MY_NODE_MODULE_ISOLATE_DECL
313
+ DWORD bytes_needed = 0, totalJobs = 0;
314
+ BOOL bError = EnumJobsW(*iPrinterHandle, 0, iTotalJobs, 2, NULL, bytes_needed, &bytes_needed, &totalJobs);
315
+ MemValue<JOB_INFO_2W> jobs(bytes_needed);
316
+ if(!jobs)
317
+ {
318
+ std::string error_str("Error on allocating memory for jobs: ");
319
+ error_str += getLastErrorCodeAndMessage();
320
+ v8::Local<v8::Object> result_printer_job = V8_VALUE_NEW_DEFAULT(Object);
321
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("error"), V8_STRING_NEW_UTF8(error_str.c_str()));
322
+ Nan::Set(result_printer_jobs, 0, result_printer_job);
323
+ return std::string("");
324
+ }
325
+ DWORD dummy_bytes = 0;
326
+ bError = EnumJobsW(*iPrinterHandle, 0, iTotalJobs, 2, (LPBYTE)jobs.get(), bytes_needed, &dummy_bytes, &totalJobs);
327
+ if(!bError)
328
+ {
329
+ std::string error_str("Error on EnumJobsW: ");
330
+ error_str += getLastErrorCodeAndMessage();
331
+ v8::Local<v8::Object> result_printer_job = V8_VALUE_NEW_DEFAULT(Object);
332
+ Nan::Set(result_printer_job, V8_STRING_NEW_UTF8("error"), V8_STRING_NEW_UTF8(error_str.c_str()));
333
+ Nan::Set(result_printer_jobs, 0, result_printer_job);
334
+ return std::string("");
335
+ }
336
+ JOB_INFO_2W *job = jobs.get();
337
+ for(DWORD i = 0; i < totalJobs; ++i, ++job)
338
+ {
339
+ v8::Local<v8::Object> result_printer_job = V8_VALUE_NEW_DEFAULT(Object);
340
+ parseJobObject(job, result_printer_job);
341
+ Nan::Set(result_printer_jobs, i, result_printer_job);
342
+ }
343
+ return std::string("");
344
+ }
345
+
346
+ std::string parsePrinterInfo(const PRINTER_INFO_2W *printer, v8::Local<v8::Object> result_printer, PrinterHandle& iPrinterHandle)
347
+ {
348
+ MY_NODE_MODULE_ISOLATE_DECL
349
+ #define ADD_V8_STRING_PROPERTY(name, key) if((printer->##key != NULL) && (*printer->##key != L'\0')) \
350
+ { \
351
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8(#name), V8_STRING_NEW_2BYTES((uint16_t*)printer->##key)); \
352
+ }
353
+ //LPTSTR pPrinterName;
354
+ ADD_V8_STRING_PROPERTY(name, pPrinterName)
355
+ //LPTSTR pServerName;
356
+ ADD_V8_STRING_PROPERTY(serverName, pServerName)
357
+ //LPTSTR pShareName;
358
+ ADD_V8_STRING_PROPERTY(shareName, pShareName)
359
+ //LPTSTR pPortName;
360
+ ADD_V8_STRING_PROPERTY(portName, pPortName)
361
+ //LPTSTR pDriverName;
362
+ ADD_V8_STRING_PROPERTY(driverName, pDriverName)
363
+ //LPTSTR pComment;
364
+ ADD_V8_STRING_PROPERTY(comment, pComment)
365
+ //LPTSTR pLocation;
366
+ ADD_V8_STRING_PROPERTY(location, pLocation)
367
+ //LPTSTR pSepFile;
368
+ ADD_V8_STRING_PROPERTY(sepFile, pSepFile)
369
+ //LPTSTR pPrintProcessor;
370
+ ADD_V8_STRING_PROPERTY(printProcessor, pPrintProcessor)
371
+ //LPTSTR pDatatype;
372
+ ADD_V8_STRING_PROPERTY(datatype, pDatatype)
373
+ //LPTSTR pParameters;
374
+ ADD_V8_STRING_PROPERTY(parameters, pParameters)
375
+ #undef ADD_V8_STRING_PROPERTY
376
+ //DWORD Status;
377
+ // statuses from:
378
+ // http://msdn.microsoft.com/en-gb/library/windows/desktop/dd162845(v=vs.85).aspx
379
+ v8::Local<v8::Array> result_printer_status = V8_VALUE_NEW_DEFAULT(Array);
380
+ int i_status = 0;
381
+ for(StatusMapType::const_iterator itStatus = getStatusMap().begin(); itStatus != getStatusMap().end(); ++itStatus)
382
+ {
383
+ if(printer->Status & itStatus->second)
384
+ {
385
+ Nan::Set(result_printer_status, i_status, V8_STRING_NEW_UTF8(itStatus->first.c_str()));
386
+ ++i_status;
387
+ }
388
+ }
389
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("status"), result_printer_status);
390
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("statusNumber"), V8_VALUE_NEW(Number, printer->Status));
391
+ //DWORD Attributes;
392
+ v8::Local<v8::Array> result_printer_attributes = V8_VALUE_NEW_DEFAULT(Array);
393
+ int i_attribute = 0;
394
+ for(StatusMapType::const_iterator itAttribute = getAttributeMap().begin(); itAttribute != getAttributeMap().end(); ++itAttribute)
395
+ {
396
+ if(printer->Attributes & itAttribute->second)
397
+ {
398
+ Nan::Set(result_printer_attributes, i_attribute, V8_STRING_NEW_UTF8(itAttribute->first.c_str()));
399
+ ++i_attribute;
400
+ }
401
+ }
402
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("attributes"), result_printer_attributes);
403
+ //DWORD Priority;
404
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("priority"), V8_VALUE_NEW(Number, printer->Priority));
405
+ //DWORD DefaultPriority;
406
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("defaultPriority"), V8_VALUE_NEW(Number, printer->DefaultPriority));
407
+ //DWORD cJobs;
408
+ //Nan::Set(result_printer, V8_STRING_NEW_UTF8("jobs"), V8_VALUE_NEW(Number, printer->cJobs));
409
+ //DWORD AveragePPM;
410
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("averagePPM"), V8_VALUE_NEW(Number, printer->AveragePPM));
411
+
412
+ //DWORD StartTime;
413
+ if(printer->StartTime > 0)
414
+ {
415
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("startTime"), V8_VALUE_NEW(Number, printer->StartTime));
416
+ }
417
+ //DWORD UntilTime;
418
+ if(printer->UntilTime > 0)
419
+ {
420
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("untilTime"), V8_VALUE_NEW(Number, printer->UntilTime));
421
+ }
422
+
423
+ //TODO: to finish to extract all data
424
+ //LPDEVMODE pDevMode;
425
+ //PSECURITY_DESCRIPTOR pSecurityDescriptor;
426
+
427
+ if(printer->cJobs > 0)
428
+ {
429
+ v8::Local<v8::Array> result_printer_jobs = V8_VALUE_NEW(Array, printer->cJobs);
430
+ // get jobs
431
+ std::string error_str = retrieveAndParseJobs(printer->pPrinterName, printer->cJobs, result_printer_jobs, iPrinterHandle);
432
+ if(!error_str.empty())
433
+ {
434
+ return error_str;
435
+ }
436
+ Nan::Set(result_printer, V8_STRING_NEW_UTF8("jobs"), result_printer_jobs);
437
+ }
438
+ return "";
439
+ }
440
+ }
441
+
442
+ MY_NODE_MODULE_CALLBACK(getPrinters)
443
+ {
444
+ MY_NODE_MODULE_HANDLESCOPE;
445
+ DWORD printers_size = 0;
446
+ DWORD printers_size_bytes = 0, dummyBytes = 0;
447
+ DWORD Level = 2;
448
+ DWORD flags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;// https://msdn.microsoft.com/en-us/library/cc244669.aspx
449
+ // First try to retrieve the number of printers
450
+ BOOL bError = EnumPrintersW(flags, NULL, 2, NULL, 0, &printers_size_bytes, &printers_size);
451
+ // allocate the required memmory
452
+ MemValue<PRINTER_INFO_2W> printers(printers_size_bytes);
453
+ if(!printers)
454
+ {
455
+ RETURN_EXCEPTION_STR("Error on allocating memory for printers");
456
+ }
457
+
458
+ bError = EnumPrintersW(flags, NULL, 2, (LPBYTE)(printers.get()), printers_size_bytes, &dummyBytes, &printers_size);
459
+ if(!bError)
460
+ {
461
+ std::string error_str("Error on EnumPrinters: ");
462
+ error_str += getLastErrorCodeAndMessage();
463
+ RETURN_EXCEPTION_STR(error_str.c_str());
464
+ }
465
+ v8::Local<v8::Array> result = V8_VALUE_NEW(Array, printers_size);
466
+ // http://msdn.microsoft.com/en-gb/library/windows/desktop/dd162845(v=vs.85).aspx
467
+ PRINTER_INFO_2W *printer = printers.get();
468
+ DWORD i = 0;
469
+ for(; i < printers_size; ++i, ++printer)
470
+ {
471
+ v8::Local<v8::Object> result_printer = V8_VALUE_NEW_DEFAULT(Object);
472
+ PrinterHandle printerHandle((LPWSTR)(printer->pPrinterName));
473
+ std::string error_str = parsePrinterInfo(printer, result_printer, printerHandle);
474
+ if(!error_str.empty())
475
+ {
476
+ RETURN_EXCEPTION_STR(error_str.c_str());
477
+ }
478
+ Nan::Set(result, i, result_printer);
479
+ }
480
+ MY_NODE_MODULE_RETURN_VALUE(result);
481
+ }
482
+
483
+ MY_NODE_MODULE_CALLBACK(getDefaultPrinterName)
484
+ {
485
+ MY_NODE_MODULE_HANDLESCOPE;
486
+ // size in chars of the printer name: https://msdn.microsoft.com/en-us/library/windows/desktop/dd144876(v=vs.85).aspx
487
+ DWORD cSize = 0;
488
+ GetDefaultPrinterW(NULL, &cSize);
489
+
490
+ if(cSize == 0) {
491
+ MY_NODE_MODULE_RETURN_VALUE(V8_STRING_NEW_UTF8(""));
492
+ }
493
+
494
+ MemValue<uint16_t> bPrinterName(cSize*sizeof(uint16_t));
495
+ BOOL res = GetDefaultPrinterW((LPWSTR)(bPrinterName.get()), &cSize);
496
+
497
+ if(!res) {
498
+ MY_NODE_MODULE_RETURN_VALUE(V8_STRING_NEW_UTF8(""));
499
+ }
500
+
501
+ MY_NODE_MODULE_RETURN_VALUE(V8_STRING_NEW_2BYTES((uint16_t*)bPrinterName.get()));
502
+ }
503
+
504
+ MY_NODE_MODULE_CALLBACK(getPrinter)
505
+ {
506
+ MY_NODE_MODULE_HANDLESCOPE;
507
+ REQUIRE_ARGUMENTS(iArgs, 1);
508
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 0, printername);
509
+
510
+ // Open a handle to the printer.
511
+ PrinterHandle printerHandle((LPWSTR)(*printername));
512
+ if(!printerHandle)
513
+ {
514
+ std::string error_str("error on PrinterHandle: ");
515
+ error_str += getLastErrorCodeAndMessage();
516
+ RETURN_EXCEPTION_STR(error_str.c_str());
517
+ }
518
+ DWORD printers_size_bytes = 0, dummyBytes = 0;
519
+ GetPrinterW(*printerHandle, 2, NULL, printers_size_bytes, &printers_size_bytes);
520
+ MemValue<PRINTER_INFO_2W> printer(printers_size_bytes);
521
+ if(!printer)
522
+ {
523
+ RETURN_EXCEPTION_STR("Error on allocating memory for printers");
524
+ }
525
+ BOOL bOK = GetPrinterW(*printerHandle, 2, (LPBYTE)(printer.get()), printers_size_bytes, &printers_size_bytes);
526
+ if(!bOK)
527
+ {
528
+ std::string error_str("Error on GetPrinter: ");
529
+ error_str += getLastErrorCodeAndMessage();
530
+ RETURN_EXCEPTION_STR(error_str.c_str());
531
+ }
532
+ v8::Local<v8::Object> result_printer = V8_VALUE_NEW_DEFAULT(Object);
533
+ std::string error_str = parsePrinterInfo(printer.get(), result_printer, printerHandle);
534
+ if(!error_str.empty())
535
+ {
536
+ RETURN_EXCEPTION_STR(error_str.c_str());
537
+ }
538
+
539
+ MY_NODE_MODULE_RETURN_VALUE(result_printer);
540
+ }
541
+
542
+ MY_NODE_MODULE_CALLBACK(getPrinterDriverOptions)
543
+ {
544
+ MY_NODE_MODULE_HANDLESCOPE;
545
+ RETURN_EXCEPTION_STR("not supported on windows");
546
+ }
547
+
548
+ MY_NODE_MODULE_CALLBACK(getJob)
549
+ {
550
+ MY_NODE_MODULE_HANDLESCOPE;
551
+ REQUIRE_ARGUMENTS(iArgs, 2);
552
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 0, printername);
553
+ REQUIRE_ARGUMENT_INTEGER(iArgs, 1, jobId);
554
+ if(jobId < 0)
555
+ {
556
+ RETURN_EXCEPTION_STR("Wrong job number");
557
+ }
558
+ // Open a handle to the printer.
559
+ PrinterHandle printerHandle((LPWSTR)(*printername));
560
+ if(!printerHandle)
561
+ {
562
+ std::string error_str("error on PrinterHandle: ");
563
+ error_str += getLastErrorCodeAndMessage();
564
+ RETURN_EXCEPTION_STR(error_str.c_str());
565
+ }
566
+ DWORD size_bytes = 0, dummyBytes = 0;
567
+ GetJobW(*printerHandle, static_cast<DWORD>(jobId), 2, NULL, size_bytes, &size_bytes);
568
+ MemValue<JOB_INFO_2W> job(size_bytes);
569
+ if(!job)
570
+ {
571
+ RETURN_EXCEPTION_STR("Error on allocating memory for printers");
572
+ }
573
+ BOOL bOK = GetJobW(*printerHandle, static_cast<DWORD>(jobId), 2, (LPBYTE)job.get(), size_bytes, &dummyBytes);
574
+ if(!bOK)
575
+ {
576
+ std::string error_str("Error on GetJob. Wrong job id or it was deleted: ");
577
+ error_str += getLastErrorCodeAndMessage();
578
+ RETURN_EXCEPTION_STR(error_str.c_str());
579
+ }
580
+ v8::Local<v8::Object> result_printer_job = V8_VALUE_NEW_DEFAULT(Object);
581
+ parseJobObject(job.get(), result_printer_job);
582
+ MY_NODE_MODULE_RETURN_VALUE(result_printer_job);
583
+ }
584
+
585
+ MY_NODE_MODULE_CALLBACK(setJob)
586
+ {
587
+ MY_NODE_MODULE_HANDLESCOPE;
588
+ REQUIRE_ARGUMENTS(iArgs, 3);
589
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 0, printername);
590
+ REQUIRE_ARGUMENT_INTEGER(iArgs, 1, jobId);
591
+ REQUIRE_ARGUMENT_STRING(iArgs, 2, jobCommandV8);
592
+ if(jobId < 0)
593
+ {
594
+ RETURN_EXCEPTION_STR("Wrong job number");
595
+ }
596
+ std::string jobCommandStr(*jobCommandV8);
597
+ StatusMapType::const_iterator itJobCommand = getJobCommandMap().find(jobCommandStr);
598
+ if(itJobCommand == getJobCommandMap().end())
599
+ {
600
+ RETURN_EXCEPTION_STR("wrong job command. use getSupportedJobCommands to see the possible commands");
601
+ }
602
+ DWORD jobCommand = itJobCommand->second;
603
+ // Open a handle to the printer.
604
+ PrinterHandle printerHandle((LPWSTR)(*printername));
605
+ if(!printerHandle)
606
+ {
607
+ std::string error_str("error on PrinterHandle: ");
608
+ error_str += getLastErrorCodeAndMessage();
609
+ RETURN_EXCEPTION_STR(error_str.c_str());
610
+ }
611
+ // TODO: add the possibility to set job properties
612
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162978(v=vs.85).aspx
613
+ BOOL ok = SetJobW(*printerHandle, (DWORD)jobId, 0, NULL, jobCommand);
614
+ MY_NODE_MODULE_RETURN_VALUE(V8_VALUE_NEW(Boolean, ok == TRUE));
615
+ }
616
+
617
+ MY_NODE_MODULE_CALLBACK(getSupportedJobCommands)
618
+ {
619
+ MY_NODE_MODULE_HANDLESCOPE;
620
+ v8::Local<v8::Array> result = V8_VALUE_NEW_DEFAULT(Array);
621
+ int i = 0;
622
+ for(StatusMapType::const_iterator itJob = getJobCommandMap().begin(); itJob != getJobCommandMap().end(); ++itJob)
623
+ {
624
+ Nan::Set(result, i++, V8_STRING_NEW_UTF8(itJob->first.c_str()));
625
+ }
626
+ MY_NODE_MODULE_RETURN_VALUE(result);
627
+ }
628
+
629
+ MY_NODE_MODULE_CALLBACK(getSupportedPrintFormats)
630
+ {
631
+ MY_NODE_MODULE_HANDLESCOPE;
632
+ v8::Local<v8::Array> result = V8_VALUE_NEW_DEFAULT(Array);
633
+ int format_i = 0;
634
+
635
+ LPTSTR name = NULL;
636
+ DWORD numBytes = 0, processorsNum = 0;
637
+
638
+ // Check the amount of bytes required
639
+ LPWSTR nullVal = NULL;
640
+ EnumPrintProcessorsW(nullVal, nullVal, 1, (LPBYTE)(NULL), numBytes, &numBytes, &processorsNum);
641
+ MemValue<_PRINTPROCESSOR_INFO_1W> processors(numBytes);
642
+ // Retrieve processors
643
+ BOOL isOK = EnumPrintProcessorsW(nullVal, nullVal, 1, (LPBYTE)(processors.get()), numBytes, &numBytes, &processorsNum);
644
+
645
+ if(!isOK) {
646
+ std::string error_str("error on EnumPrintProcessorsW: ");
647
+ error_str += getLastErrorCodeAndMessage();
648
+ RETURN_EXCEPTION_STR(error_str.c_str());
649
+ }
650
+
651
+ _PRINTPROCESSOR_INFO_1W *pProcessor = processors.get();
652
+
653
+ for(DWORD processor_i = 0; processor_i < processorsNum; ++processor_i, ++pProcessor) {
654
+ numBytes = 0;
655
+ DWORD dataTypesNum = 0;
656
+ EnumPrintProcessorDatatypesW(nullVal, pProcessor->pName, 1, (LPBYTE)(NULL), numBytes, &numBytes, &dataTypesNum);
657
+ MemValue<_DATATYPES_INFO_1W> dataTypes(numBytes);
658
+ isOK = EnumPrintProcessorDatatypesW(nullVal, pProcessor->pName, 1, (LPBYTE)(dataTypes.get()), numBytes, &numBytes, &dataTypesNum);
659
+
660
+ if(!isOK) {
661
+ std::string error_str("error on EnumPrintProcessorDatatypesW: ");
662
+ error_str += getLastErrorCodeAndMessage();
663
+ RETURN_EXCEPTION_STR(error_str.c_str());
664
+ }
665
+
666
+ _DATATYPES_INFO_1W *pDataType = dataTypes.get();
667
+ for(DWORD j = 0; j < dataTypesNum; ++j, ++pDataType) {
668
+ Nan::Set(result, format_i++, V8_STRING_NEW_2BYTES((uint16_t*)(pDataType->pName)));
669
+ }
670
+ }
671
+
672
+ MY_NODE_MODULE_RETURN_VALUE(result);
673
+ }
674
+
675
+ MY_NODE_MODULE_CALLBACK(PrintDirect)
676
+ {
677
+ MY_NODE_MODULE_HANDLESCOPE;
678
+ //TODO: to move in an unique place win and posix input parameters processing
679
+ REQUIRE_ARGUMENTS(iArgs, 5);
680
+
681
+ // can be string or buffer
682
+ if(iArgs.Length()<=0)
683
+ {
684
+ RETURN_EXCEPTION_STR("Argument 0 missing");
685
+ }
686
+
687
+ std::string data;
688
+ v8::Local<v8::Value> arg0(iArgs[0]);
689
+ if (!getStringOrBufferFromV8Value(arg0, data))
690
+ {
691
+ RETURN_EXCEPTION_STR("Argument 0 must be a string or Buffer");
692
+ }
693
+
694
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 1, printername);
695
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 2, docname);
696
+ REQUIRE_ARGUMENT_STRINGW(iArgs, 3, type);
697
+
698
+ BOOL bStatus = true;
699
+ // Open a handle to the printer.
700
+ PrinterHandle printerHandle((LPWSTR)(*printername));
701
+ DOC_INFO_1W DocInfo;
702
+ DWORD dwJob = 0L;
703
+ DWORD dwBytesWritten = 0L;
704
+
705
+ if (!printerHandle)
706
+ {
707
+ std::string error_str("error on PrinterHandle: ");
708
+ error_str += getLastErrorCodeAndMessage();
709
+ RETURN_EXCEPTION_STR(error_str.c_str());
710
+ }
711
+
712
+ // Fill in the structure with info about this "document."
713
+ DocInfo.pDocName = (LPWSTR)(*docname);
714
+ DocInfo.pOutputFile = NULL;
715
+ DocInfo.pDatatype = (LPWSTR)(*type);
716
+
717
+ // Inform the spooler the document is beginning.
718
+ dwJob = StartDocPrinterW(*printerHandle, 1, (LPBYTE)&DocInfo );
719
+ if (dwJob > 0) {
720
+ // Start a page.
721
+ bStatus = StartPagePrinter(*printerHandle);
722
+ if (bStatus) {
723
+ // Send the data to the printer.
724
+ //TODO: check with sizeof(LPTSTR) is the same as sizeof(char)
725
+ bStatus = WritePrinter( *printerHandle, (LPVOID)(data.c_str()), (DWORD)data.size(), &dwBytesWritten);
726
+ EndPagePrinter(*printerHandle);
727
+ }else{
728
+ std::string error_str("StartPagePrinter error: ");
729
+ error_str += getLastErrorCodeAndMessage();
730
+ RETURN_EXCEPTION_STR(error_str.c_str());
731
+ }
732
+ // Inform the spooler that the document is ending.
733
+ EndDocPrinter(*printerHandle);
734
+ }else{
735
+ std::string error_str("StartDocPrinterW error: ");
736
+ error_str += getLastErrorCodeAndMessage();
737
+ RETURN_EXCEPTION_STR(error_str.c_str());
738
+ }
739
+ // Check to see if correct number of bytes were written.
740
+ if (dwBytesWritten != data.size()) {
741
+ RETURN_EXCEPTION_STR("not sent all bytes");
742
+ }
743
+ MY_NODE_MODULE_RETURN_VALUE(V8_VALUE_NEW(Number, dwJob));
744
+ }
745
+
746
+ MY_NODE_MODULE_CALLBACK(PrintFile)
747
+ {
748
+ MY_NODE_MODULE_HANDLESCOPE;
749
+ RETURN_EXCEPTION_STR("Not yet implemented on Windows");
750
+ }