@esslassi/electron-printer 0.0.2 → 0.0.5

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.
@@ -1,77 +0,0 @@
1
- #ifndef NODE_PRINTER_HPP
2
- #define NODE_PRINTER_HPP
3
- #include "macros.hh"
4
-
5
-
6
- MY_NODE_MODULE_CALLBACK(SayMyName);
7
- MY_NODE_MODULE_CALLBACK(getPrinters);
8
- MY_NODE_MODULE_CALLBACK(getDefaultPrinterName);
9
- MY_NODE_MODULE_CALLBACK(printDirect);
10
- MY_NODE_MODULE_CALLBACK(getPrinter);
11
- MY_NODE_MODULE_CALLBACK(printFile);
12
- MY_NODE_MODULE_CALLBACK(getSupportedPrintFormats);
13
-
14
-
15
-
16
- /**
17
- * @brief A base class template for managing a pointer to a value of type Type.
18
- *
19
- * This class provides basic functionality for managing a pointer to a value,
20
- * including construction, destruction, and access methods.
21
- *
22
- * @tparam Type The type of the value being managed.
23
- */
24
-
25
- template<typename Type>
26
- class MemValueBase
27
- {
28
- public:
29
- /**
30
- * @brief Default constructor. Initializes the pointer to NULL.
31
- */
32
- MemValueBase(): _value(NULL) {}
33
-
34
- /**
35
- * @brief Virtual destructor. The allocated memory will be deallocated.
36
- */
37
- virtual ~MemValueBase() {}
38
- /**
39
- * @brief Gets the pointer to the value.
40
- *
41
- * @return A pointer to the value of type Type.
42
- */
43
- Type * get() {return _value; }
44
- /**
45
- * @brief Overloaded arrow operator to access the value.
46
- *
47
- * @return A pointer to the value of type Type.
48
- */
49
- Type * operator ->() { return &_value; }
50
- /**
51
- * @brief Conversion operator to check if the pointer is not NULL.
52
- *
53
- * @return True if the pointer is not NULL, false otherwise.
54
- */
55
- operator bool() const { return (_value != NULL); }
56
- protected:
57
- Type *_value; /**< Pointer to the value of type Type. */
58
- /**
59
- * @brief Virtual method to free the allocated memory.
60
- *
61
- * This method can be overridden by derived classes to provide custom
62
- * memory deallocation logic.
63
- */
64
- virtual void free() {};
65
- };
66
-
67
- /**
68
- * Try to extract a string or buffer from a N-API value.
69
- * @param value - source N-API value
70
- * @param oData - destination data
71
- * @return TRUE if value is a string or buffer, FALSE otherwise
72
- */
73
-
74
- bool getStringOrBufferFromNapiValue(const Napi::Value& value, std::string& oData);
75
-
76
-
77
- #endif
@@ -1,586 +0,0 @@
1
- #include "node_printer.hpp"
2
- #if _MSC_VER
3
- #include <windows.h>
4
- #include <Winspool.h>
5
- #include <Wingdi.h>
6
- #pragma comment(lib, "Winspool.lib")
7
- #else
8
- #error "Unsupported compiler for windows. Feel free to add it."
9
- #endif
10
-
11
- #include <string>
12
- #include <map>
13
- #include <utility>
14
- #include <sstream>
15
- #include <cstdio>
16
-
17
- // Utility function to output messages
18
- void ConsolePrint(const std::string& message) {
19
- printf("%s\n", message.c_str());
20
- fflush(stdout); // Ensure the output is flushed immediately
21
- }
22
-
23
- // Function to convert std::u16string to std::wstring
24
- std::wstring u16stringToWString(const std::u16string& u16str) {
25
- return std::wstring(u16str.begin(), u16str.end());
26
- }
27
-
28
- namespace{
29
- typedef std::map<std::string, DWORD> StatusMapType;
30
-
31
- /** Memory value class management to avoid memory leak
32
- */
33
- template<typename Type>
34
- class MemValue: public MemValueBase<Type> {
35
- public:
36
- /** Constructor of allocating iSizeKbytes bytes memory;
37
- * @param iSizeKbytes size in bytes of required allocating memory
38
- */
39
- MemValue(const DWORD iSizeKbytes) {
40
- _value = (Type*)malloc(iSizeKbytes);
41
- }
42
-
43
- ~MemValue () {
44
- free();
45
- }
46
-
47
- Type* get() {
48
- return _value;
49
- }
50
- protected:
51
- virtual void free() {
52
- if(_value != NULL)
53
- {
54
- ::free(_value);
55
- _value = NULL;
56
- }
57
- }
58
-
59
- private:
60
- Type* _value; // Declaration of the member variable
61
- };
62
-
63
- struct PrinterHandle
64
- {
65
- PrinterHandle(LPWSTR iPrinterName)
66
- {
67
- _ok = OpenPrinterW(iPrinterName, &_printer, NULL);
68
- }
69
- ~PrinterHandle()
70
- {
71
- if(_ok)
72
- {
73
- ClosePrinter(_printer);
74
- }
75
- }
76
- operator HANDLE() {return _printer;}
77
- operator bool() { return (!!_ok);}
78
- HANDLE& operator *() { return _printer;}
79
- HANDLE* operator ->() { return &_printer;}
80
- const HANDLE& operator ->() const { return _printer;}
81
- HANDLE _printer;
82
- BOOL _ok;
83
- };
84
-
85
- const StatusMapType& getStatusMap()
86
- {
87
- static StatusMapType result;
88
- if(!result.empty())
89
- {
90
- return result;
91
- }
92
- // add only first time
93
- #define STATUS_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
94
- STATUS_PRINTER_ADD("BUSY", PRINTER_STATUS_BUSY);
95
- STATUS_PRINTER_ADD("DOOR-OPEN", PRINTER_STATUS_DOOR_OPEN);
96
- STATUS_PRINTER_ADD("ERROR", PRINTER_STATUS_ERROR);
97
- STATUS_PRINTER_ADD("INITIALIZING", PRINTER_STATUS_INITIALIZING);
98
- STATUS_PRINTER_ADD("IO-ACTIVE", PRINTER_STATUS_IO_ACTIVE);
99
- STATUS_PRINTER_ADD("MANUAL-FEED", PRINTER_STATUS_MANUAL_FEED);
100
- STATUS_PRINTER_ADD("NO-TONER", PRINTER_STATUS_NO_TONER);
101
- STATUS_PRINTER_ADD("NOT-AVAILABLE", PRINTER_STATUS_NOT_AVAILABLE);
102
- STATUS_PRINTER_ADD("OFFLINE", PRINTER_STATUS_OFFLINE);
103
- STATUS_PRINTER_ADD("OUT-OF-MEMORY", PRINTER_STATUS_OUT_OF_MEMORY);
104
- STATUS_PRINTER_ADD("OUTPUT-BIN-FULL", PRINTER_STATUS_OUTPUT_BIN_FULL);
105
- STATUS_PRINTER_ADD("PAGE-PUNT", PRINTER_STATUS_PAGE_PUNT);
106
- STATUS_PRINTER_ADD("PAPER-JAM", PRINTER_STATUS_PAPER_JAM);
107
- STATUS_PRINTER_ADD("PAPER-OUT", PRINTER_STATUS_PAPER_OUT);
108
- STATUS_PRINTER_ADD("PAPER-PROBLEM", PRINTER_STATUS_PAPER_PROBLEM);
109
- STATUS_PRINTER_ADD("PAUSED", PRINTER_STATUS_PAUSED);
110
- STATUS_PRINTER_ADD("PENDING-DELETION", PRINTER_STATUS_PENDING_DELETION);
111
- STATUS_PRINTER_ADD("POWER-SAVE", PRINTER_STATUS_POWER_SAVE);
112
- STATUS_PRINTER_ADD("PRINTING", PRINTER_STATUS_PRINTING);
113
- STATUS_PRINTER_ADD("PROCESSING", PRINTER_STATUS_PROCESSING);
114
- STATUS_PRINTER_ADD("SERVER-UNKNOWN", PRINTER_STATUS_SERVER_UNKNOWN);
115
- STATUS_PRINTER_ADD("TONER-LOW", PRINTER_STATUS_TONER_LOW);
116
- STATUS_PRINTER_ADD("USER-INTERVENTION", PRINTER_STATUS_USER_INTERVENTION);
117
- STATUS_PRINTER_ADD("WAITING", PRINTER_STATUS_WAITING);
118
- STATUS_PRINTER_ADD("WARMING-UP", PRINTER_STATUS_WARMING_UP);
119
- #undef STATUS_PRINTER_ADD
120
- return result;
121
- }
122
-
123
- const StatusMapType& getJobStatusMap()
124
- {
125
- static StatusMapType result;
126
- if(!result.empty())
127
- {
128
- return result;
129
- }
130
- // add only first time
131
- #define STATUS_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
132
- // Common statuses
133
- STATUS_PRINTER_ADD("PRINTING", JOB_STATUS_PRINTING);
134
- STATUS_PRINTER_ADD("PRINTED", JOB_STATUS_PRINTED);
135
- STATUS_PRINTER_ADD("PAUSED", JOB_STATUS_PAUSED);
136
-
137
- // Specific statuses
138
- STATUS_PRINTER_ADD("BLOCKED-DEVQ", JOB_STATUS_BLOCKED_DEVQ);
139
- STATUS_PRINTER_ADD("DELETED", JOB_STATUS_DELETED);
140
- STATUS_PRINTER_ADD("DELETING", JOB_STATUS_DELETING);
141
- STATUS_PRINTER_ADD("ERROR", JOB_STATUS_ERROR);
142
- STATUS_PRINTER_ADD("OFFLINE", JOB_STATUS_OFFLINE);
143
- STATUS_PRINTER_ADD("PAPEROUT", JOB_STATUS_PAPEROUT);
144
- STATUS_PRINTER_ADD("RESTART", JOB_STATUS_RESTART);
145
- STATUS_PRINTER_ADD("SPOOLING", JOB_STATUS_SPOOLING);
146
- STATUS_PRINTER_ADD("USER-INTERVENTION", JOB_STATUS_USER_INTERVENTION);
147
- // XP and later
148
- #ifdef JOB_STATUS_COMPLETE
149
- STATUS_PRINTER_ADD("COMPLETE", JOB_STATUS_COMPLETE);
150
- #endif
151
- #ifdef JOB_STATUS_RETAINED
152
- STATUS_PRINTER_ADD("RETAINED", JOB_STATUS_RETAINED);
153
- #endif
154
-
155
- #undef STATUS_PRINTER_ADD
156
- return result;
157
- }
158
-
159
- const StatusMapType& getAttributeMap()
160
- {
161
- static StatusMapType result;
162
- if(!result.empty())
163
- {
164
- return result;
165
- }
166
- // add only first time
167
- #define ATTRIBUTE_PRINTER_ADD(value, type) result.insert(std::make_pair(value, type))
168
- ATTRIBUTE_PRINTER_ADD("DIRECT", PRINTER_ATTRIBUTE_DIRECT);
169
- ATTRIBUTE_PRINTER_ADD("DO-COMPLETE-FIRST", PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST);
170
- ATTRIBUTE_PRINTER_ADD("ENABLE-DEVQ", PRINTER_ATTRIBUTE_ENABLE_DEVQ);
171
- ATTRIBUTE_PRINTER_ADD("HIDDEN", PRINTER_ATTRIBUTE_HIDDEN);
172
- ATTRIBUTE_PRINTER_ADD("KEEPPRINTEDJOBS", PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS);
173
- ATTRIBUTE_PRINTER_ADD("LOCAL", PRINTER_ATTRIBUTE_LOCAL);
174
- ATTRIBUTE_PRINTER_ADD("NETWORK", PRINTER_ATTRIBUTE_NETWORK);
175
- ATTRIBUTE_PRINTER_ADD("PUBLISHED", PRINTER_ATTRIBUTE_PUBLISHED);
176
- ATTRIBUTE_PRINTER_ADD("QUEUED", PRINTER_ATTRIBUTE_QUEUED);
177
- ATTRIBUTE_PRINTER_ADD("RAW-ONLY", PRINTER_ATTRIBUTE_RAW_ONLY);
178
- ATTRIBUTE_PRINTER_ADD("SHARED", PRINTER_ATTRIBUTE_SHARED);
179
- ATTRIBUTE_PRINTER_ADD("OFFLINE", PRINTER_ATTRIBUTE_WORK_OFFLINE);
180
- // XP
181
- #ifdef PRINTER_ATTRIBUTE_FAX
182
- ATTRIBUTE_PRINTER_ADD("FAX", PRINTER_ATTRIBUTE_FAX);
183
- #endif
184
- // vista
185
- #ifdef PRINTER_ATTRIBUTE_FRIENDLY_NAME
186
- ATTRIBUTE_PRINTER_ADD("FRIENDLY-NAME", PRINTER_ATTRIBUTE_FRIENDLY_NAME);
187
- ATTRIBUTE_PRINTER_ADD("MACHINE", PRINTER_ATTRIBUTE_MACHINE);
188
- ATTRIBUTE_PRINTER_ADD("PUSHED-USER", PRINTER_ATTRIBUTE_PUSHED_USER);
189
- ATTRIBUTE_PRINTER_ADD("PUSHED-MACHINE", PRINTER_ATTRIBUTE_PUSHED_MACHINE);
190
- #endif
191
- // server 2003
192
- #ifdef PRINTER_ATTRIBUTE_TS
193
- ATTRIBUTE_PRINTER_ADD("TS", PRINTER_ATTRIBUTE_TS);
194
- #endif
195
- #undef ATTRIBUTE_PRINTER_ADD
196
- return result;
197
- }
198
-
199
- const StatusMapType& getJobCommandMap()
200
- {
201
- static StatusMapType result;
202
- if(!result.empty())
203
- {
204
- return result;
205
- }
206
- // add only first time
207
- #define COMMAND_JOB_ADD(value, type) result.insert(std::make_pair(value, type))
208
- COMMAND_JOB_ADD("CANCEL", JOB_CONTROL_CANCEL);
209
- COMMAND_JOB_ADD("PAUSE", JOB_CONTROL_PAUSE);
210
- COMMAND_JOB_ADD("RESTART", JOB_CONTROL_RESTART);
211
- COMMAND_JOB_ADD("RESUME", JOB_CONTROL_RESUME);
212
- COMMAND_JOB_ADD("DELETE", JOB_CONTROL_DELETE);
213
- COMMAND_JOB_ADD("SENT-TO-PRINTER", JOB_CONTROL_SENT_TO_PRINTER);
214
- COMMAND_JOB_ADD("LAST-PAGE-EJECTED", JOB_CONTROL_LAST_PAGE_EJECTED);
215
- #ifdef JOB_CONTROL_RETAIN
216
- COMMAND_JOB_ADD("RETAIN", JOB_CONTROL_RETAIN);
217
- #endif
218
- #ifdef JOB_CONTROL_RELEASE
219
- COMMAND_JOB_ADD("RELEASE", JOB_CONTROL_RELEASE);
220
- #endif
221
- #undef COMMAND_JOB_ADD
222
- return result;
223
- }
224
-
225
- void parseJobObject(JOB_INFO_2W *job, Napi::Object result_printer_job)
226
- {
227
- Napi::Env env = result_printer_job.Env(); // info.Env();
228
- // Common fields
229
- ADD_NAPI_NUMBER_PROPERTY(result_printer_job, "id", job->JobId);
230
- // Example usage of the string property macro
231
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "printerName", pPrinterName);
232
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "user", pUserName);
233
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "format", pDatatype);
234
- result_printer_job.Set(Napi::String::New(env, "priority"), Napi::Number::New(env, job->Priority));
235
- result_printer_job.Set(Napi::String::New(env, "size"), Napi::Number::New(env, job->Size));
236
- Napi::Array result_printer_job_status = Napi::Array::New(env);
237
- int i_status = 0;
238
- for (const auto &itStatus : getJobStatusMap())
239
- {
240
- if (job->Status & itStatus.second)
241
- {
242
- result_printer_job_status.Set(i_status++, Napi::String::New(env, itStatus.first.c_str()));
243
- }
244
- }
245
- if ((job->pStatus != NULL) && (*job->pStatus != L'\0'))
246
- {
247
- result_printer_job_status.Set(i_status++, Napi::String::New(env, (char16_t *)job->pStatus));
248
- }
249
- result_printer_job.Set(Napi::String::New(env, "status"), result_printer_job_status);
250
- // Specific fields
251
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "machineName", pMachineName);
252
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "document", pDocument);
253
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "notifyName", pNotifyName);
254
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "printProcessor", pPrintProcessor);
255
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "parameters", pParameters);
256
- ADD_NAPI_STRING_PROPERTY(result_printer_job, "driverName", pDriverName);
257
- result_printer_job.Set(Napi::String::New(env, "position"), Napi::Number::New(env, job->Position));
258
- result_printer_job.Set(Napi::String::New(env, "startTime"), Napi::Number::New(env, job->StartTime));
259
- result_printer_job.Set(Napi::String::New(env, "untilTime"), Napi::Number::New(env, job->UntilTime));
260
- result_printer_job.Set(Napi::String::New(env, "totalPages"), Napi::Number::New(env, job->TotalPages));
261
- result_printer_job.Set(Napi::String::New(env, "time"), Napi::Number::New(env, job->Time));
262
- result_printer_job.Set(Napi::String::New(env, "pagesPrinted"), Napi::Number::New(env, job->PagesPrinted));
263
-
264
- }
265
- std::string getLastErrorCodeAndMessage() {
266
- std::ostringstream s;
267
- DWORD erroCode = GetLastError();
268
- s << "code: " << erroCode;
269
- DWORD retSize;
270
- LPTSTR pTemp = NULL;
271
- retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
272
- FORMAT_MESSAGE_FROM_SYSTEM|
273
- FORMAT_MESSAGE_ARGUMENT_ARRAY,
274
- NULL,
275
- erroCode,
276
- LANG_NEUTRAL,
277
- (LPTSTR)&pTemp,
278
- 0,
279
- NULL );
280
- if (retSize && pTemp != NULL) {
281
- //pTemp[strlen(pTemp)-2]='\0'; //remove cr and newline character
282
- //TODO: check if it is needed to convert c string to std::string
283
- std::string stringMessage(pTemp);
284
- s << ", message: " << stringMessage;
285
- LocalFree((HLOCAL)pTemp);
286
- }
287
-
288
- return s.str();
289
- }
290
-
291
- std::string retrieveAndParseJobs(const LPWSTR iPrinterName, const DWORD& iTotalJobs, Napi::Object result_printer_jobs, PrinterHandle& iPrinterHandle)
292
- {
293
- Napi::Env env = result_printer_jobs.Env();
294
- DWORD bytes_needed = 0, totalJobs = 0;
295
- BOOL bError = EnumJobsW(*iPrinterHandle, 0, iTotalJobs, 2, NULL, bytes_needed, &bytes_needed, &totalJobs);
296
- MemValue<JOB_INFO_2W> jobs(bytes_needed);
297
- if(!jobs)
298
- {
299
- std::string error_str("Error on allocating memory for jobs: ");
300
- error_str += getLastErrorCodeAndMessage();
301
- Napi::Object result_printer_job = Napi::Object::New(env);
302
- result_printer_job.Set(NAPI_STRING_NEW_UTF8(env, "error"), NAPI_STRING_NEW_UTF8(env, error_str.c_str()));
303
- result_printer_jobs.Set(uint32_t(0), result_printer_job);
304
- return std::string("");
305
- }
306
- DWORD dummy_bytes = 0;
307
- bError = EnumJobsW(*iPrinterHandle, 0, iTotalJobs, 2, (LPBYTE)jobs.get(), bytes_needed, &dummy_bytes, &totalJobs);
308
- if(!bError)
309
- {
310
- std::string error_str("Error on EnumJobsW: ");
311
- error_str += getLastErrorCodeAndMessage();
312
- Napi::Object result_printer_job = Napi::Object::New(env);
313
- result_printer_job.Set(NAPI_STRING_NEW_UTF8(env, "error"), NAPI_STRING_NEW_UTF8(env, error_str.c_str()));
314
- result_printer_jobs.Set(uint32_t(0), result_printer_job);
315
- return std::string("");
316
- }
317
- JOB_INFO_2W *job = jobs.get();
318
- for(DWORD i = 0; i < totalJobs; ++i, ++job)
319
- {
320
- Napi::Object result_printer_job = Napi::Object::New(env);
321
- parseJobObject(job, result_printer_job);
322
- result_printer_jobs.Set(i, result_printer_job);
323
- }
324
- return std::string("");
325
- }
326
-
327
- std::string parsePrinterInfo(const PRINTER_INFO_2W *printer, Napi::Object result_printer, PrinterHandle& iPrinterHandle) {
328
- Napi::Env env = result_printer.Env();
329
- #define ADD_V8_STRING_PROPERTY(name, key) if((printer->##key != NULL) && (*printer->##key != L'\0')) \
330
- { \
331
- result_printer.Set(Napi::String::New(result_printer.Env(), #name), Napi::String::New(result_printer.Env(), (char16_t*)printer->##key)); \
332
- }
333
- //LPTSTR pPrinterName;
334
- ADD_V8_STRING_PROPERTY(name, pPrinterName)
335
- //LPTSTR pServerName;
336
- ADD_V8_STRING_PROPERTY(serverName, pServerName)
337
- //LPTSTR pShareName;
338
- ADD_V8_STRING_PROPERTY(shareName, pShareName)
339
- //LPTSTR pPortName;
340
- ADD_V8_STRING_PROPERTY(portName, pPortName)
341
- //LPTSTR pDriverName;
342
- ADD_V8_STRING_PROPERTY(driverName, pDriverName)
343
- //LPTSTR pComment;
344
- ADD_V8_STRING_PROPERTY(comment, pComment)
345
- //LPTSTR pLocation;
346
- ADD_V8_STRING_PROPERTY(location, pLocation)
347
- //LPTSTR pSepFile;
348
- ADD_V8_STRING_PROPERTY(sepFile, pSepFile)
349
- //LPTSTR pPrintProcessor;
350
- ADD_V8_STRING_PROPERTY(printProcessor, pPrintProcessor)
351
- //LPTSTR pDatatype;
352
- ADD_V8_STRING_PROPERTY(datatype, pDatatype)
353
- //LPTSTR pParameters;
354
- ADD_V8_STRING_PROPERTY(parameters, pParameters)
355
- #undef ADD_V8_STRING_PROPERTY
356
- //DWORD Status;
357
- // statuses from:
358
- // http://msdn.microsoft.com/en-gb/library/windows/desktop/dd162845(v=vs.85).aspx
359
- Napi::Array result_printer_status = Napi::Array::New(env);
360
- int i_status = 0;
361
- for (const auto& itStatus : getStatusMap()) {
362
- if (printer->Status & itStatus.second) {
363
- result_printer_status.Set(i_status++, Napi::String::New(env, itStatus.first.c_str()));
364
- }
365
- }
366
- result_printer.Set(Napi::String::New(env, "status"), result_printer_status);
367
- result_printer.Set(Napi::String::New(env, "statusNumber"), Napi::Number::New(env, printer->Status));
368
- // Attributes
369
- Napi::Array result_printer_attributes = Napi::Array::New(env);
370
- int i_attribute = 0;
371
- for (const auto& itAttribute : getAttributeMap()) {
372
- if (printer->Attributes & itAttribute.second) {
373
- result_printer_attributes.Set(i_attribute++, Napi::String::New(env, itAttribute.first.c_str()));
374
- }
375
- result_printer.Set(Napi::String::New(env, "attributes"), result_printer_attributes);
376
- // Other properties
377
- result_printer.Set(Napi::String::New(env, "priority"), Napi::Number::New(env, printer->Priority));
378
- result_printer.Set(Napi::String::New(env, "defaultPriority"), Napi::Number::New(env, printer->DefaultPriority));
379
- result_printer.Set(Napi::String::New(env, "averagePPM"), Napi::Number::New(env, printer->AveragePPM));
380
-
381
- if (printer->StartTime > 0) {
382
- result_printer.Set(Napi::String::New(env, "startTime"), Napi::Number::New(env, printer->StartTime));
383
- }
384
- if (printer->UntilTime > 0) {
385
- result_printer.Set(Napi::String::New(env, "untilTime"), Napi::Number::New(env, printer->UntilTime));
386
- }
387
- if (printer->cJobs > 0) {
388
- Napi::Array result_printer_jobs = Napi::Array::New(env, printer->cJobs);
389
- std::string error_str = retrieveAndParseJobs(printer->pPrinterName, printer->cJobs, result_printer_jobs, iPrinterHandle);
390
- if (!error_str.empty()) {
391
- return error_str;
392
- }
393
- result_printer.Set(Napi::String::New(env, "jobs"), result_printer_jobs);
394
- }
395
-
396
-
397
- }
398
-
399
- return "";
400
- }
401
-
402
-
403
- }
404
-
405
- MY_NODE_MODULE_CALLBACK(getPrinters)
406
- {
407
- MY_NODE_MODULE_HANDLESCOPE;
408
- DWORD printers_size = 0;
409
- DWORD printers_size_bytes = 0, dummyBytes = 0;
410
- DWORD Level = 2;
411
- DWORD flags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
412
- // First try to retrieve the number of printers
413
- BOOL bError = EnumPrintersW(flags, NULL, Level, NULL, 0, &printers_size_bytes, &printers_size);
414
- // Check for errors in the first call
415
- if (!bError && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
416
- RETURN_EXCEPTION_STR(MY_NODE_MODULE_ENV, "Error retrieving printer size.");
417
- }
418
-
419
- // Check if we got a valid size
420
- if (printers_size_bytes == 0) {
421
- RETURN_EXCEPTION_STR(info.Env(), "No printers found or invalid size returned.");
422
- }
423
-
424
- // Allocate the required memory
425
- MemValue<PRINTER_INFO_2W> printers(printers_size_bytes);
426
- if (!printers.get()) // Make sure to check the pointer
427
- {
428
- RETURN_EXCEPTION_STR(MY_NODE_MODULE_ENV, "Error allocating memory for printers");
429
- }
430
-
431
- // Second call to retrieve printer information
432
- bError = EnumPrintersW(flags, NULL, Level, (LPBYTE)(printers.get()), printers_size_bytes, &dummyBytes, &printers_size);
433
- if (!bError)
434
- {
435
- std::string error_str("Error on EnumPrinters");
436
- error_str += getLastErrorCodeAndMessage();
437
- RETURN_EXCEPTION_STR(MY_NODE_MODULE_ENV, error_str.c_str());
438
- }
439
-
440
- // Prepare result array
441
- Napi::Array result = Napi::Array::New(MY_NODE_MODULE_ENV, printers_size);
442
- PRINTER_INFO_2W *printer = printers.get();
443
- DWORD i = 0;
444
- for (; i < printers_size; ++i, ++printer)
445
- {
446
- Napi::Object a_printer = Napi::Object::New(MY_NODE_MODULE_ENV);
447
- PrinterHandle printerHandle((LPWSTR)(printer->pPrinterName));
448
- std::string error_str = parsePrinterInfo(printer, a_printer, printerHandle);
449
- if (!error_str.empty())
450
- {
451
- RETURN_EXCEPTION_STR(MY_NODE_MODULE_ENV, error_str.c_str());
452
- }
453
- result.Set(i, a_printer);
454
- }
455
- MY_NODE_MODULE_RETURN_VALUE(result);
456
- }
457
-
458
- MY_NODE_MODULE_CALLBACK(getDefaultPrinterName)
459
- {
460
- MY_NODE_MODULE_HANDLESCOPE;
461
- DWORD cSize = 0;
462
- GetDefaultPrinterW(NULL, &cSize);
463
-
464
- if(cSize == 0) {
465
- MY_NODE_MODULE_RETURN_VALUE(NAPI_STRING_NEW_UTF8(MY_NODE_MODULE_ENV, ""));
466
- }
467
-
468
- MemValue<uint16_t> bPrinterName(cSize*sizeof(uint16_t));
469
- BOOL res = GetDefaultPrinterW((LPWSTR)(bPrinterName.get()), &cSize);
470
-
471
- if(!res) {
472
- MY_NODE_MODULE_RETURN_VALUE(NAPI_STRING_NEW_UTF8(MY_NODE_MODULE_ENV, ""));
473
- }
474
- MY_NODE_MODULE_RETURN_VALUE(NAPI_STRING_NEW_2BYTES(MY_NODE_MODULE_ENV, bPrinterName.get()));
475
- }
476
-
477
- MY_NODE_MODULE_CALLBACK(printDirect)
478
- {
479
- MY_NODE_MODULE_HANDLESCOPE;
480
- // Ensure the correct number of arguments
481
- if (info.Length() < 5) {
482
- Napi::TypeError::New(env, "Expected 5 arguments").ThrowAsJavaScriptException();
483
- return env.Null();
484
- }
485
-
486
- // Check and extract the first argument (string or buffer)
487
- std::string data;
488
- if (!getStringOrBufferFromNapiValue(info[0], data)) {
489
- Napi::TypeError::New(env, "Argument 0 must be a string or Buffer").ThrowAsJavaScriptException();
490
- return env.Null();
491
- }
492
-
493
- // Check and extract the second argument (string)
494
- if (!info[1].IsString()) {
495
- Napi::TypeError::New(env, "Argument 1 must be a string").ThrowAsJavaScriptException();
496
- return env.Null();
497
- }
498
- std::u16string u16PrinterName = info[1].As<Napi::String>().Utf16Value();
499
- std::wstring printername = u16stringToWString(u16PrinterName);
500
-
501
- // Check and extract the third argument (string)
502
- if (!info[2].IsString()) {
503
- Napi::TypeError::New(env, "Argument 2 must be a string").ThrowAsJavaScriptException();
504
- return env.Null();
505
- }
506
- std::u16string u16DocName = info[2].As<Napi::String>().Utf16Value();
507
- std::wstring docname = u16stringToWString(u16DocName);
508
-
509
- // Check and extract the fourth argument (string)
510
- if (!info[3].IsString()) {
511
- Napi::TypeError::New(env, "Argument 3 must be a string").ThrowAsJavaScriptException();
512
- return env.Null();
513
- }
514
- std::u16string u16Type = info[3].As<Napi::String>().Utf16Value();
515
- std::wstring type = u16stringToWString(u16Type);
516
-
517
- // Convert std::wstring to LPWSTR (mutable wide string pointer)
518
- std::vector<wchar_t> printernameMutable(printername.begin(), printername.end());
519
- printernameMutable.push_back(L'\0'); // Ensure null-termination
520
-
521
- PrinterHandle printerHandle(printernameMutable.data());
522
- if (!printerHandle) {
523
- std::string error_str("Error on PrinterHandle: ");
524
- error_str += getLastErrorCodeAndMessage();
525
- Napi::TypeError::New(env, error_str).ThrowAsJavaScriptException();
526
- return env.Null();
527
- }
528
-
529
- // Fill in the structure with info about this "document."
530
- DOC_INFO_1W DocInfo;
531
- DocInfo.pDocName = const_cast<LPWSTR>(docname.c_str());
532
- DocInfo.pOutputFile = NULL;
533
- DocInfo.pDatatype = const_cast<LPWSTR>(type.c_str());
534
-
535
- // Inform the spooler the document is beginning.
536
- DWORD dwJob = StartDocPrinterW(*printerHandle, 1, (LPBYTE)&DocInfo);
537
- if (dwJob > 0) {
538
- // Start a page.
539
- BOOL bStatus = StartPagePrinter(*printerHandle);
540
- if (bStatus) {
541
- // Send the data to the printer.
542
- DWORD dwBytesWritten = 0L;
543
- bStatus = WritePrinter(*printerHandle, (LPVOID)(data.c_str()), (DWORD)data.size(), &dwBytesWritten);
544
- EndPagePrinter(*printerHandle);
545
-
546
- // Check to see if correct number of bytes were written.
547
- if (dwBytesWritten != data.size()) {
548
- Napi::TypeError::New(env, "Not all bytes were sent").ThrowAsJavaScriptException();
549
- return env.Null();
550
- }
551
- } else {
552
- std::string error_str("StartPagePrinter error: ");
553
- error_str += getLastErrorCodeAndMessage();
554
- Napi::TypeError::New(env, error_str).ThrowAsJavaScriptException();
555
- return env.Null();
556
- }
557
- // Inform the spooler that the document is ending.
558
- EndDocPrinter(*printerHandle);
559
- } else {
560
- std::string error_str("StartDocPrinterW error: ");
561
- error_str += getLastErrorCodeAndMessage();
562
- Napi::TypeError::New(env, error_str).ThrowAsJavaScriptException();
563
- return env.Null();
564
- }
565
-
566
- MY_NODE_MODULE_RETURN_VALUE(Napi::Number::New(env, dwJob));
567
- }
568
-
569
-
570
- MY_NODE_MODULE_CALLBACK(getPrinter)
571
- {
572
- MY_NODE_MODULE_HANDLESCOPE;
573
- MY_NODE_MODULE_RETURN_VALUE(NAPI_STRING_NEW_UTF8(MY_NODE_MODULE_ENV, "getPrinter is not implemented yet, request for a PR if required"));
574
- }
575
-
576
- MY_NODE_MODULE_CALLBACK(printFile)
577
- {
578
- MY_NODE_MODULE_HANDLESCOPE;
579
- RETURN_EXCEPTION(MY_NODE_MODULE_ENV, "Not yet implemented on Windows");
580
- }
581
-
582
- MY_NODE_MODULE_CALLBACK(getSupportedPrintFormats)
583
- {
584
- MY_NODE_MODULE_HANDLESCOPE;
585
- RETURN_EXCEPTION(MY_NODE_MODULE_ENV, "Not yet implemented, Request for a PR");
586
- }
@@ -1,18 +0,0 @@
1
- const assert = require('assert/strict');
2
- const { test, beforeEach } = require('node:test');
3
-
4
- let addon;
5
-
6
- beforeEach(() => {
7
- addon = require('../lib');
8
- });
9
-
10
- test('Ensure getDefaultPrinterName function exists', (t) => {
11
- assert.ok(addon.getDefaultPrinterName, 'getDefaultPrinterName function should exist');
12
- assert.strictEqual(typeof addon.getDefaultPrinterName, 'function', 'getDefaultPrinterName should be a function');
13
- });
14
-
15
- test('Ensure getDefaultPrinterName returns a string', (t) => {
16
- const result = addon.getDefaultPrinterName();
17
- assert.strictEqual(typeof result, "string", 'getDefaultPrinterName should return a string');
18
- });