win_print 0.1.1
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.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Rakefile +18 -0
- data/ext/extconf.rb +6 -0
- data/ext/extension.c +43 -0
- data/ext/raw_print.c +153 -0
- data/ext/raw_print.h +2 -0
- data/lib/win_print.rb +35 -0
- data/lib/win_print/version.rb +3 -0
- data/test/win_print_test.rb +18 -0
- data/win_print.gemspec +27 -0
- metadata +100 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: d4c9ec9f2cb3dbe56a56e7be657a11a328b560f5
|
|
4
|
+
data.tar.gz: b3cd3d756d12f372f4eba2066a8779ee10d757e4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1da3c04d2a40ce3cfd9cde2f3848b01f2a7daad91fbf3805fca1bd0c111054f34604945409c8a6aa2e5049da348f1b09483960607c68629d6ce585b05991affa
|
|
7
|
+
data.tar.gz: 0c59f7faf4dd4884c2ddbfd328f5df0b313d1b30d975b7a8c329a55e172427a4f74569ee8ab0fc8a5428fb9c47629fec7080d5b00bd603c272044d3d5bfb1cef
|
data/Gemfile
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
|
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
|
5
|
+
t.libs << "test"
|
|
6
|
+
t.libs << "ext"
|
|
7
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
task :compile do
|
|
11
|
+
puts "Compiling extension"
|
|
12
|
+
`cd ext && make clean`
|
|
13
|
+
`cd ext && ruby extconf.rb`
|
|
14
|
+
`cd ext && make`
|
|
15
|
+
puts "Done"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
task :default => :test
|
data/ext/extconf.rb
ADDED
data/ext/extension.c
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#include "ruby/ruby.h"
|
|
2
|
+
#include "ruby/encoding.h"
|
|
3
|
+
#include "raw_print.h"
|
|
4
|
+
|
|
5
|
+
// Get printer names of all system printers.
|
|
6
|
+
static VALUE get_printer_names(VALUE self) {
|
|
7
|
+
char errMsg[1024];
|
|
8
|
+
VALUE arr = rb_ary_new();
|
|
9
|
+
int success = GetPrinterNames(arr, errMsg);
|
|
10
|
+
if (success == 0) {
|
|
11
|
+
rb_enc_raise(rb_enc_find("CP1252"), rb_eRuntimeError, errMsg);
|
|
12
|
+
}
|
|
13
|
+
return arr;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Send raw data to a system printer.
|
|
17
|
+
static VALUE raw_print(VALUE self, VALUE printer_name, VALUE data, VALUE doc_name) {
|
|
18
|
+
Check_Type(printer_name, T_STRING);
|
|
19
|
+
Check_Type(data, T_STRING);
|
|
20
|
+
Check_Type(doc_name, T_STRING);
|
|
21
|
+
|
|
22
|
+
char* pointer_printer_name = StringValueCStr(printer_name);
|
|
23
|
+
char* pointer_data = RSTRING_PTR(StringValue(data));
|
|
24
|
+
int data_len = RSTRING_LEN(StringValue(data));
|
|
25
|
+
char* pointer_doc_name = StringValueCStr(doc_name);
|
|
26
|
+
|
|
27
|
+
char errMsg[1024];
|
|
28
|
+
int boolean_out = RawDataToPrinter( pointer_printer_name, pointer_data, data_len, pointer_doc_name, errMsg );
|
|
29
|
+
if (boolean_out == 0) {
|
|
30
|
+
rb_enc_raise(rb_enc_find("CP1252"), rb_eRuntimeError, errMsg);
|
|
31
|
+
}
|
|
32
|
+
return Qtrue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Register class methods:
|
|
36
|
+
// WinPrint::Native.get_printer_names
|
|
37
|
+
// WinPrint::Native.raw_print
|
|
38
|
+
void Init_extension(void) {
|
|
39
|
+
VALUE WinPrint = rb_define_module("WinPrint");
|
|
40
|
+
VALUE Native = rb_define_class_under(WinPrint, "Native", rb_cObject);
|
|
41
|
+
rb_define_singleton_method(Native, "get_printer_names", get_printer_names, 0);
|
|
42
|
+
rb_define_singleton_method(Native, "raw_print", raw_print, 3);
|
|
43
|
+
}
|
data/ext/raw_print.c
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#include <ruby/ruby.h>
|
|
2
|
+
#include <windows.h>
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
|
|
5
|
+
// This code is partially based on examples from here:
|
|
6
|
+
// https://support.microsoft.com/de-de/help/138594/howto-send-raw-data-to-a-printer-by-using-the-win32-api
|
|
7
|
+
|
|
8
|
+
// **********************************************************************
|
|
9
|
+
// GetErrorMessage - get message from error code information
|
|
10
|
+
//
|
|
11
|
+
// Params:
|
|
12
|
+
// dwError - the error code, usually from GetLastError()
|
|
13
|
+
// lpString - some caller-defined text to include with the error info
|
|
14
|
+
// errMsg - buffer to store the message in
|
|
15
|
+
//
|
|
16
|
+
// Returns: void
|
|
17
|
+
//
|
|
18
|
+
void GetErrorMessage( DWORD dwError, LPCTSTR lpString, char *errMsg )
|
|
19
|
+
{
|
|
20
|
+
#define MAX_MSG_BUF_SIZE 512
|
|
21
|
+
TCHAR *msgBuf;
|
|
22
|
+
DWORD cMsgLen;
|
|
23
|
+
|
|
24
|
+
cMsgLen = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
|
|
25
|
+
FORMAT_MESSAGE_ALLOCATE_BUFFER | 40, NULL, dwError,
|
|
26
|
+
MAKELANGID(0, SUBLANG_ENGLISH_US), (LPTSTR) &msgBuf,
|
|
27
|
+
MAX_MSG_BUF_SIZE, NULL );
|
|
28
|
+
sprintf( errMsg, TEXT("%s Error [%d]: %s"), lpString, dwError, msgBuf );
|
|
29
|
+
LocalFree( msgBuf );
|
|
30
|
+
#undef MAX_MSG_BUF_SIZE
|
|
31
|
+
}
|
|
32
|
+
// **********************************************************************
|
|
33
|
+
|
|
34
|
+
// **********************************************************************
|
|
35
|
+
// GetPrinterNames - return a ruby array with printer names
|
|
36
|
+
//
|
|
37
|
+
// Params:
|
|
38
|
+
// arr - ruby array to put the printer names in
|
|
39
|
+
// errMsg - Buffer to store the error message in
|
|
40
|
+
//
|
|
41
|
+
// Returns: TRUE for success, FALSE for failure.
|
|
42
|
+
//
|
|
43
|
+
BOOL GetPrinterNames(VALUE arr, char *errMsg) {
|
|
44
|
+
BOOL success = TRUE;
|
|
45
|
+
PRINTER_INFO_1* prninfo = NULL;
|
|
46
|
+
DWORD needed, returned;
|
|
47
|
+
|
|
48
|
+
// find required size for the buffer
|
|
49
|
+
EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &returned);
|
|
50
|
+
|
|
51
|
+
// allocate array of PRINTER_INFO structures
|
|
52
|
+
prninfo = (PRINTER_INFO_1*) GlobalAlloc(GPTR, needed);
|
|
53
|
+
|
|
54
|
+
// call again
|
|
55
|
+
if (!EnumPrinters(PRINTER_ENUM_LOCAL, NULL,
|
|
56
|
+
1, (LPBYTE) prninfo, needed, &needed, &returned)) {
|
|
57
|
+
GetErrorMessage( GetLastError(), TEXT("EnumPrinters"), errMsg );
|
|
58
|
+
success = FALSE;
|
|
59
|
+
} else {
|
|
60
|
+
for (DWORD i=0; i < returned; i++) {
|
|
61
|
+
if ((prninfo[i].Flags & PRINTER_ENUM_ICON8) == PRINTER_ENUM_ICON8) {
|
|
62
|
+
rb_ary_push(arr, rb_str_new2(prninfo[i].pName));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
GlobalFree(prninfo);
|
|
68
|
+
|
|
69
|
+
return success;
|
|
70
|
+
}
|
|
71
|
+
// **********************************************************************
|
|
72
|
+
|
|
73
|
+
// **********************************************************************
|
|
74
|
+
// RawDataToPrinter - sends binary data directly to a printer
|
|
75
|
+
//
|
|
76
|
+
// Params:
|
|
77
|
+
// szPrinterName - NULL terminated string specifying printer name
|
|
78
|
+
// lpData - Pointer to raw data bytes
|
|
79
|
+
// dwCount - Length of lpData in bytes
|
|
80
|
+
// docName - Name of the document, displayed in the printer queue
|
|
81
|
+
// errMsg - Buffer to store the error message in
|
|
82
|
+
//
|
|
83
|
+
// Returns: TRUE for success, FALSE for failure.
|
|
84
|
+
//
|
|
85
|
+
BOOL RawDataToPrinter( LPTSTR szPrinterName, LPBYTE lpData, DWORD dwCount, LPTSTR docName, char *errMsg )
|
|
86
|
+
{
|
|
87
|
+
HANDLE hPrinter;
|
|
88
|
+
DOC_INFO_1 DocInfo;
|
|
89
|
+
DWORD dwJob;
|
|
90
|
+
DWORD dwBytesWritten;
|
|
91
|
+
|
|
92
|
+
// Need a handle to the printer.
|
|
93
|
+
if( ! OpenPrinter( szPrinterName, &hPrinter, NULL ) )
|
|
94
|
+
{
|
|
95
|
+
GetErrorMessage( GetLastError(), TEXT("OpenPrinter"), errMsg );
|
|
96
|
+
return FALSE;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Fill in the structure with info about this "document."
|
|
100
|
+
DocInfo.pDocName = docName;
|
|
101
|
+
DocInfo.pOutputFile = NULL;
|
|
102
|
+
DocInfo.pDatatype = TEXT("RAW");
|
|
103
|
+
// Inform the spooler the document is beginning.
|
|
104
|
+
if( (dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo )) == 0 )
|
|
105
|
+
{
|
|
106
|
+
GetErrorMessage( GetLastError(), TEXT("StartDocPrinter"), errMsg );
|
|
107
|
+
ClosePrinter( hPrinter );
|
|
108
|
+
return FALSE;
|
|
109
|
+
}
|
|
110
|
+
// Start a page.
|
|
111
|
+
if( ! StartPagePrinter( hPrinter ) )
|
|
112
|
+
{
|
|
113
|
+
GetErrorMessage( GetLastError(), TEXT("StartPagePrinter"), errMsg );
|
|
114
|
+
EndDocPrinter( hPrinter );
|
|
115
|
+
ClosePrinter( hPrinter );
|
|
116
|
+
return FALSE;
|
|
117
|
+
}
|
|
118
|
+
// Send the data to the printer.
|
|
119
|
+
if( ! WritePrinter( hPrinter, lpData, dwCount, &dwBytesWritten ) )
|
|
120
|
+
{
|
|
121
|
+
GetErrorMessage( GetLastError(), TEXT("WritePrinter"), errMsg );
|
|
122
|
+
EndPagePrinter( hPrinter );
|
|
123
|
+
EndDocPrinter( hPrinter );
|
|
124
|
+
ClosePrinter( hPrinter );
|
|
125
|
+
return FALSE;
|
|
126
|
+
}
|
|
127
|
+
// End the page.
|
|
128
|
+
if( ! EndPagePrinter( hPrinter ) )
|
|
129
|
+
{
|
|
130
|
+
GetErrorMessage( GetLastError(), TEXT("EndPagePrinter"), errMsg );
|
|
131
|
+
EndDocPrinter( hPrinter );
|
|
132
|
+
ClosePrinter( hPrinter );
|
|
133
|
+
return FALSE;
|
|
134
|
+
}
|
|
135
|
+
// Inform the spooler that the document is ending.
|
|
136
|
+
if( ! EndDocPrinter( hPrinter ) )
|
|
137
|
+
{
|
|
138
|
+
GetErrorMessage( GetLastError(), TEXT("EndDocPrinter"), errMsg );
|
|
139
|
+
ClosePrinter( hPrinter );
|
|
140
|
+
return FALSE;
|
|
141
|
+
}
|
|
142
|
+
// Tidy up the printer handle.
|
|
143
|
+
ClosePrinter( hPrinter );
|
|
144
|
+
// Check to see if correct number of bytes were written.
|
|
145
|
+
if( dwBytesWritten != dwCount )
|
|
146
|
+
{
|
|
147
|
+
sprintf( errMsg, TEXT("Wrote %d bytes instead of requested %d bytes.\n"), dwBytesWritten, dwCount );
|
|
148
|
+
return FALSE;
|
|
149
|
+
}
|
|
150
|
+
return TRUE;
|
|
151
|
+
}
|
|
152
|
+
// End RawDataToPrinter
|
|
153
|
+
// **********************************************************************
|
data/ext/raw_print.h
ADDED
data/lib/win_print.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require "extension"
|
|
2
|
+
require "win_print/version"
|
|
3
|
+
|
|
4
|
+
# Ruby wrappers for native C functions.
|
|
5
|
+
# Here we ensure correct encodings before calling C.
|
|
6
|
+
module WinPrint
|
|
7
|
+
# Get list of printer names available on the system.
|
|
8
|
+
#
|
|
9
|
+
# Example:
|
|
10
|
+
# >> WinPrint.get_printer_names
|
|
11
|
+
# => ["Microsoft XPS Document Writer", "Microsoft Print to PDF", "Fax"]
|
|
12
|
+
|
|
13
|
+
def self.get_printer_names
|
|
14
|
+
WinPrint::Native.get_printer_names.map{|pr| pr.force_encoding("CP1252").encode("UTF-8")}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Send raw data to a system printer.
|
|
18
|
+
#
|
|
19
|
+
# Example:
|
|
20
|
+
# >> WinPrint.raw_print("Microsoft Print to PDF", "Some raw data.", "Test Job from WinPrint gem")
|
|
21
|
+
# => true
|
|
22
|
+
#
|
|
23
|
+
# Arguments:
|
|
24
|
+
# printer_name: (String)
|
|
25
|
+
# data: (String) raw data to be sent to the printer
|
|
26
|
+
# job_name: (String) will be displayed e.g. in the printer queue
|
|
27
|
+
#
|
|
28
|
+
# Note: For data, the encoding matters and the data will be sent as-is to the printer.
|
|
29
|
+
# Will raise RuntimeError if something goes wrong.
|
|
30
|
+
|
|
31
|
+
def self.raw_print(printer_name, data, job_name)
|
|
32
|
+
WinPrint::Native.raw_print(printer_name.encode("CP1252"), data,
|
|
33
|
+
job_name.encode("CP1252", invalid: :replace, undef: :replace, replace: ''))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "minitest/autorun"
|
|
2
|
+
require "win_print"
|
|
3
|
+
|
|
4
|
+
class WinPrintTest < Minitest::Test
|
|
5
|
+
def test_printer_names
|
|
6
|
+
# Just run the method and see if it dies (or hopefully not).
|
|
7
|
+
printers = WinPrint.get_printer_names
|
|
8
|
+
assert !printers.nil? # Should be an array.
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_printing_on_non_existing
|
|
12
|
+
# Try to print on a non-existing printer and verify, if we get the right exception.
|
|
13
|
+
exception = assert_raises RuntimeError do
|
|
14
|
+
WinPrint.raw_print("A printer with this name should definitely not exist.", "Some data.", "And a job name")
|
|
15
|
+
end
|
|
16
|
+
assert_includes exception.message, "[1801]"
|
|
17
|
+
end
|
|
18
|
+
end
|
data/win_print.gemspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require "win_print/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "win_print"
|
|
7
|
+
spec.version = WinPrint::VERSION
|
|
8
|
+
spec.authors = ["Martin Schuster"]
|
|
9
|
+
spec.email = "schuster@schul-logistik.de"
|
|
10
|
+
spec.homepage = "http://github.com/mrschuster/win_print"
|
|
11
|
+
spec.license = "MIT"
|
|
12
|
+
spec.summary = "Gem for raw printing on windows"
|
|
13
|
+
|
|
14
|
+
spec.test_files = Dir['test/*']
|
|
15
|
+
spec.extensions = ["ext/extconf.rb"]
|
|
16
|
+
spec.files = ['Rakefile', 'win_print.gemspec', 'Gemfile'] + Dir["ext/*.c", "ext/*.h", "ext/*.rb", "lib/**/*"]
|
|
17
|
+
|
|
18
|
+
spec.add_development_dependency "bundler", ">=1.16"
|
|
19
|
+
spec.add_development_dependency "rake"
|
|
20
|
+
spec.add_development_dependency "minitest"
|
|
21
|
+
|
|
22
|
+
spec.description = <<-EOL
|
|
23
|
+
The WinPrint library offers a way to send raw data to
|
|
24
|
+
a system printer on windows. It also allows to fetch the
|
|
25
|
+
printer list.
|
|
26
|
+
EOL
|
|
27
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: win_print
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Martin Schuster
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-08-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.16'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.16'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
description: |2
|
|
56
|
+
The WinPrint library offers a way to send raw data to
|
|
57
|
+
a system printer on windows. It also allows to fetch the
|
|
58
|
+
printer list.
|
|
59
|
+
email: schuster@schul-logistik.de
|
|
60
|
+
executables: []
|
|
61
|
+
extensions:
|
|
62
|
+
- ext/extconf.rb
|
|
63
|
+
extra_rdoc_files: []
|
|
64
|
+
files:
|
|
65
|
+
- Gemfile
|
|
66
|
+
- Rakefile
|
|
67
|
+
- ext/extconf.rb
|
|
68
|
+
- ext/extension.c
|
|
69
|
+
- ext/raw_print.c
|
|
70
|
+
- ext/raw_print.h
|
|
71
|
+
- lib/win_print.rb
|
|
72
|
+
- lib/win_print/version.rb
|
|
73
|
+
- test/win_print_test.rb
|
|
74
|
+
- win_print.gemspec
|
|
75
|
+
homepage: http://github.com/mrschuster/win_print
|
|
76
|
+
licenses:
|
|
77
|
+
- MIT
|
|
78
|
+
metadata: {}
|
|
79
|
+
post_install_message:
|
|
80
|
+
rdoc_options: []
|
|
81
|
+
require_paths:
|
|
82
|
+
- lib
|
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - ">="
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '0'
|
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
requirements: []
|
|
94
|
+
rubyforge_project:
|
|
95
|
+
rubygems_version: 2.6.14
|
|
96
|
+
signing_key:
|
|
97
|
+
specification_version: 4
|
|
98
|
+
summary: Gem for raw printing on windows
|
|
99
|
+
test_files:
|
|
100
|
+
- test/win_print_test.rb
|