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.
@@ -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
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gemspec
@@ -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
@@ -0,0 +1,6 @@
1
+ require "mkmf"
2
+
3
+ abort "No winspool" unless have_library "winspool"
4
+ $LDFLAGS = '-lwinspool'
5
+
6
+ create_makefile "extension"
@@ -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
+ }
@@ -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
+ // **********************************************************************
@@ -0,0 +1,2 @@
1
+ BOOL GetPrinterNames(VALUE arr, char *errMsg);
2
+ BOOL RawDataToPrinter( LPTSTR szPrinterName, LPBYTE lpData, DWORD dwCount, LPTSTR docName, char *errMsg );
@@ -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,3 @@
1
+ module WinPrint
2
+ VERSION = "0.1.1"
3
+ 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
@@ -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