win32-clipboard 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.5.0 - 24-Apr-2009
2
+ * Added the Clipboard.notify_change method, which notifies you if any changes
3
+ have been made to the clipboard.
4
+ * Added support for copying file lists, bitmaps and Windows metafiles.
5
+ * Added the Clipboard.clear alias for Clipboard.empty
6
+ * The previous documentation for the Clipboard.format_available? method was
7
+ misleading. It has been corrected.
8
+ * Added rdoc for modules, classes and constants, and added some inline
9
+ code examples for some methods.
10
+ * Gemspec update for handling a deprecated method.
11
+
1
12
  == 0.4.4 - 26-Aug-2008
2
13
  * Some internal refactoring to ensure that the clipboard is closed on failure
3
14
  in a more robust fashion.
data/Rakefile CHANGED
@@ -1,20 +1,24 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
3
 
4
- desc "Install the win32-clipboard package (non-gem)"
4
+ desc "Install the win32-clipboard library (non-gem)"
5
5
  task :install do
6
6
  dest = File.join(Config::CONFIG['sitelibdir'], 'win32')
7
7
  Dir.mkdir(dest) unless File.exists? dest
8
8
  cp 'lib/win32/clipboard.rb', dest, :verbose => true
9
9
  end
10
10
 
11
- desc "Install the win32-clipboard package as a gem"
11
+ desc "Install the win32-clipboard library as a gem"
12
12
  task :install_gem do
13
13
  ruby 'win32-clipboard.gemspec'
14
14
  file = Dir["*.gem"].first
15
15
  sh "gem install #{file}"
16
16
  end
17
17
 
18
+ desc "Run the example program"
19
+ task :example do
20
+ sh "ruby -Ilib examples/clipboard_test.rb"
21
+
18
22
  Rake::TestTask.new do |t|
19
23
  t.warning = true
20
24
  t.verbose = true
@@ -1,13 +1,9 @@
1
1
  ##########################################################################
2
2
  # clipboard_test.rb (win32-clipboard)
3
3
  #
4
- # Generic test script for those without TestUnit installed, or for
5
- # general futzing.
4
+ # Generic test script for those without Test::Unit installed, or for
5
+ # general futzing. You can run this example via the 'rake example' task.
6
6
  ##########################################################################
7
- Dir.chdir('..') if File.basename(Dir.pwd) == 'examples'
8
- $LOAD_PATH.unshift(Dir.pwd)
9
- $LOAD_PATH.unshift(Dir.pwd + '/lib')
10
-
11
7
  require "win32/clipboard"
12
8
  require "pp"
13
9
  include Win32
@@ -1,31 +1,72 @@
1
1
  require 'windows/clipboard'
2
2
  require 'windows/memory'
3
3
  require 'windows/error'
4
+ require 'windows/shell'
5
+ require 'windows/library'
6
+ require 'windows/window'
4
7
  require 'windows/msvcrt/buffer'
8
+ require 'windows/gdi/metafile'
9
+ require 'windows/window/message'
10
+ require 'windows/window/classes'
5
11
 
12
+ # The Win32 module serves as a namespace only.
6
13
  module Win32
14
+ # The Clipboard class encapsulates functions that relate to the MS Windows
15
+ # clipboard.
7
16
  class Clipboard
17
+ # The Clipboard::Error class is raised if any of the Win32::Clipboard
18
+ # methods should fail.
8
19
  class Error < StandardError; end
9
20
 
10
21
  include Windows::Clipboard
11
22
  include Windows::Memory
12
23
  include Windows::Error
24
+ include Windows::Shell
25
+ include Windows::Library
26
+ include Windows::Window
13
27
  include Windows::MSVCRT::Buffer
28
+ include Windows::GDI::MetaFile
29
+ include Windows::Window::Message
30
+ include Windows::Window::Classes
14
31
 
15
32
  extend Windows::Clipboard
16
33
  extend Windows::Memory
17
34
  extend Windows::Error
35
+ extend Windows::Shell
36
+ extend Windows::Library
37
+ extend Windows::Window
18
38
  extend Windows::MSVCRT::Buffer
39
+ extend Windows::GDI::MetaFile
40
+ extend Windows::Window::Message
41
+ extend Windows::Window::Classes
19
42
 
20
- VERSION = '0.4.4'
43
+ # The version of this library
44
+ VERSION = '0.5.0'
21
45
 
22
- # Clipboard data types
23
- TEXT = CF_TEXT
24
- OEMTEXT = CF_OEMTEXT
46
+ # Clipboard formats
47
+
48
+ # Text
49
+ TEXT = CF_TEXT
50
+ OEMTEXT = CF_OEMTEXT
25
51
  UNICODETEXT = CF_UNICODETEXT
26
52
 
27
- # Sets the clipboard contents to the data that you specify. You may
28
- # optionally specify a clipboard format. The default is Clipboard::TEXT.
53
+ # Images
54
+ DIB = CF_DIB
55
+ BITMAP = CF_BITMAP
56
+
57
+ # Metafiles
58
+ ENHMETAFILE = CF_ENHMETAFILE
59
+
60
+ # Files
61
+ HDROP = CF_HDROP
62
+
63
+ # Sets the clipboard contents to the data that you specify. You may
64
+ # optionally specify a clipboard format. The default is Clipboard::TEXT.
65
+ #
66
+ # Example:
67
+ #
68
+ # # Put the string 'hello' on the clipboard
69
+ # Win32::Clipboard.set_data('hello')
29
70
  #
30
71
  def self.set_data(clip_data, format = TEXT)
31
72
  self.open
@@ -59,25 +100,51 @@ module Win32
59
100
  # specified, it will attempt to retrieve the data in that format. The
60
101
  # default is Clipboard::TEXT.
61
102
  #
62
- # If there is no data in the clipboard then an empty string is returned.
103
+ # If there is no data in the clipboard, or data is available but the
104
+ # format doesn't match the data, then an empty string is returned.
105
+ #
106
+ # Examples:
107
+ #
108
+ # # Get some plain text
109
+ # Win32::Clipboard.data # => e.g. 'hello'
110
+ #
111
+ # # Get a list of files copied from the Windows Explorer window
112
+ # Win32::Clipboard.data(Clipboard::HDROP) # => ['foo.rb', 'bar.rb']
113
+ #
114
+ # # Get a bitmap and write it to another file
115
+ # File.open('bitmap_copy', 'wb'){ |fh|
116
+ # fh.write Win32::Clipboard.data(Clipboard::DIB)
117
+ # }
63
118
  #
64
119
  def self.data(format = TEXT)
65
120
  begin
66
121
  self.open
67
- clipdata = GetClipboardData(format) || ""
122
+ if IsClipboardFormatAvailable(format)
123
+ handle = GetClipboardData(format)
124
+ case format
125
+ when TEXT, OEMTEXT, UNICODETEXT
126
+ clip_data = 0.chr * GlobalSize(handle)
127
+ memcpy(clip_data, handle, clip_data.size)
128
+ clip_data.strip!
129
+ when HDROP
130
+ clip_data = get_file_list(handle)
131
+ when ENHMETAFILE
132
+ clip_data = get_metafile_data(handle)
133
+ when DIB, BITMAP
134
+ clip_data = get_image_data(handle)
135
+ else
136
+ raise Error, 'format not supported'
137
+ end
138
+ else
139
+ clip_data = ''
140
+ end
68
141
  ensure
69
142
  self.close
70
143
  end
71
144
 
72
- clipdata
145
+ clip_data
73
146
  end
74
147
 
75
- # Singleton aliases
76
- #
77
- class << self
78
- alias :get_data :data
79
- end
80
-
81
148
  # Empties the contents of the clipboard.
82
149
  #
83
150
  def self.empty
@@ -91,6 +158,13 @@ module Win32
91
158
  self
92
159
  end
93
160
 
161
+ # Singleton aliases
162
+ #
163
+ class << self
164
+ alias :get_data :data
165
+ alias :clear :empty
166
+ end
167
+
94
168
  # Returns the number of different data formats currently on the
95
169
  # clipboard.
96
170
  #
@@ -135,6 +209,10 @@ module Win32
135
209
 
136
210
  # Returns a hash of all the current formats, with the format number as
137
211
  # the key and the format name as the value for that key.
212
+ #
213
+ # Example:
214
+ #
215
+ # Win32::Clipboard.formats # => {1 => nil, 49335 => "HTML Format"}
138
216
  #
139
217
  def self.formats
140
218
  formats = {}
@@ -167,22 +245,168 @@ module Win32
167
245
  # through 0xFFFF.
168
246
  #
169
247
  def self.register_format(format)
248
+ raise TypeError unless format.is_a?(String)
249
+
170
250
  if RegisterClipboardFormat(format) == 0
171
251
  error = "RegisterClipboardFormat() call failed: " + get_last_error
172
- raise Error, error
252
+ raise Error, error
253
+ end
254
+ end
255
+
256
+ # Sets up a notification loop that will call the provided block whenever
257
+ # there's a change to the clipboard.
258
+ #
259
+ # Example:
260
+ #
261
+ # Win32::Clipboard.notify_change{
262
+ # puts "There's been a change in the clipboard contents!"
263
+ # }
264
+ #--
265
+ # We skip the first notification because the very act of attaching the
266
+ # new window causes it to trigger once.
267
+ #
268
+ def self.notify_change(&block)
269
+ name = 'ruby-clipboard-' + Time.now.to_s
270
+ handle = CreateWindow('static', name, 0, 0, 0, 0, 0, 0, 0, 0, 0)
271
+
272
+ @first_notify = true
273
+
274
+ wnd_proc = Win32::API::Callback.new('LLLL', 'L') do |hwnd, umsg, wparam, lparam|
275
+ case umsg
276
+ when WM_DRAWCLIPBOARD
277
+ yield unless @first_notify
278
+ next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
279
+ if next_viewer != 0
280
+ PostMessage(next_viewer, umsg, wparam, lparam)
281
+ end
282
+ rv = 0
283
+ when WM_CHANGECBCHAIN
284
+ yield unless @first_notify
285
+ next_viewer = lparam if next_viewer == wparam
286
+ if next_viewer != 0
287
+ PostMessage(next_viewer, umsg, wparam, lparam)
288
+ end
289
+ rv = 0
290
+ else
291
+ rv = DefWindowProc(hwnd, umsg, wparam, lparam)
292
+ end
293
+
294
+ @first_notify = false
295
+
296
+ rv
297
+ end
298
+
299
+ old_wnd_proc = SetWindowLongPtr(handle, GWL_WNDPROC, wnd_proc.address)
300
+ next_viewer = SetClipboardViewer(handle)
301
+
302
+ SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
303
+
304
+ msg = 0.chr * 100
305
+
306
+ while true
307
+ while PeekMessage(msg, handle, 0, 0, 1)
308
+ TranslateMessage(msg)
309
+ DispatchMessage(msg)
310
+ end
311
+ sleep 0.1
173
312
  end
174
313
  end
175
314
 
176
315
  private
177
316
 
317
+ # Opens the clipboard and prevents other applications from modifying
318
+ # the clipboard content until it is closed.
319
+ #
178
320
  def self.open
179
- if 0 == OpenClipboard(0)
321
+ if 0 == OpenClipboard(nil)
180
322
  raise Error, "OpenClipboard() failed: " + get_last_error
181
323
  end
182
324
  end
183
325
 
326
+ # Close the clipboard
327
+ #
184
328
  def self.close
185
329
  CloseClipboard()
186
330
  end
331
+
332
+ # Get data for enhanced metadata files
333
+ #
334
+ def self.get_metafile_data(handle)
335
+ buf_size = GetEnhMetaFileBits(handle, 0, nil)
336
+ buf = 0.chr * buf_size
337
+ GetEnhMetaFileBits(handle, buf_size, buf)
338
+ buf
339
+ end
340
+
341
+ # Get data for bitmap files
342
+ #
343
+ def self.get_image_data(handle)
344
+ buf = nil
345
+ bmi = 0.chr * 44 # BITMAPINFO
346
+
347
+ begin
348
+ address = GlobalLock(handle)
349
+ buf_size = GlobalSize(handle)
350
+
351
+ memcpy(bmi, address, bmi.length)
352
+
353
+ size = bmi[0,4].unpack('L').first # biSize
354
+ bit_count = bmi[14,2].unpack('S').first # biBitCount
355
+ compression = bmi[16,4].unpack('L').first # biCompression
356
+ size_image = bmi[20,4].unpack('L').first # biSizeImage
357
+ clr_used = bmi[32,4].unpack('L').first # biClrUsed
358
+
359
+ size_image = buf_size + 16 if size_image == 0
360
+
361
+ # Calculate the header size
362
+ case bit_count
363
+ when 1
364
+ table_size = 2
365
+ when 4
366
+ table_size = 16
367
+ when 8
368
+ table_size = 256
369
+ when 16, 32
370
+ if compression == 0
371
+ table_size = clr_used
372
+ elsif compression == 3
373
+ table_size = 3
374
+ else
375
+ raise Error, "invalid bit/compression combination"
376
+ end
377
+ when 24
378
+ table_size = clr_used
379
+ else
380
+ raise Error, "invalid bit count"
381
+ end # case
382
+
383
+ offset = 0x36 + (table_size * 4)
384
+ buf = 0.chr * buf_size
385
+
386
+ memcpy(buf, address, buf.size)
387
+
388
+ buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + buf
389
+ ensure
390
+ GlobalUnlock(handle)
391
+ end
392
+
393
+ buf
394
+ end
395
+
396
+ # Get and return an array of file names that have been copied.
397
+ #
398
+ def self.get_file_list(handle)
399
+ array = []
400
+ count = DragQueryFile(handle, 0xFFFFFFFF, nil, 0)
401
+
402
+ 0.upto(count - 1){ |i|
403
+ length = DragQueryFile(handle, i, nil, 0) + 1
404
+ buf = 0.chr * length
405
+ DragQueryFile(handle, i, buf, buf.length)
406
+ array << buf.strip
407
+ }
408
+
409
+ array
410
+ end
187
411
  end
188
- end
412
+ end
@@ -7,34 +7,48 @@
7
7
  #
8
8
  # You should run this test case via the 'rake test' task.
9
9
  ###########################################################################
10
+ require 'rubygems'
11
+ gem 'test-unit'
12
+
10
13
  require 'win32/clipboard'
11
14
  require 'test/unit'
12
15
  include Win32
13
16
 
14
17
  class TC_Win32_ClipBoard < Test::Unit::TestCase
15
18
  def test_version
16
- assert_equal('0.4.4', Clipboard::VERSION)
19
+ assert_equal('0.5.0', Clipboard::VERSION)
17
20
  end
18
21
 
19
22
  def test_data
20
23
  assert_respond_to(Clipboard, :data)
21
24
  assert_nothing_raised{ Clipboard.data }
22
- assert_kind_of(String, Clipboard.data, 'bad data type')
23
- assert_raises(NameError){ Clipboard.data(CF_FOO) }
25
+ assert_kind_of(String, Clipboard.data)
26
+ end
27
+
28
+ def test_data_expected_errors
29
+ assert_raise(TypeError){ Clipboard.data('test') }
30
+ assert_raise(NameError){ Clipboard.data(CF_FOO) }
24
31
  end
25
32
 
26
33
  def test_get_data_alias
27
34
  assert_respond_to(Clipboard, :get_data)
28
- assert_equal(true, Clipboard.method(:data) == Clipboard.method(:get_data))
35
+ assert_true(Clipboard.method(:data) == Clipboard.method(:get_data))
29
36
  end
30
37
 
31
38
  def test_set_data
32
39
  assert_respond_to(Clipboard, :set_data)
33
40
  assert_nothing_raised{ Clipboard.set_data("foo") }
41
+ end
42
+
43
+ def test_set_data_unicode
34
44
  assert_nothing_raised{
35
45
  Clipboard.set_data('Ηελλας', Clipboard::UNICODETEXT)
36
46
  }
37
- assert_raises(NameError){ Clipboard.set_data('foo', CF_FOO) }
47
+ end
48
+
49
+ def test_set_data_expected_errors
50
+ assert_raise(ArgumentError){ Clipboard.set_data }
51
+ assert_raise(NameError){ Clipboard.set_data('foo', CF_FOO) }
38
52
  end
39
53
 
40
54
  def test_set_and_get_ascii
@@ -54,18 +68,28 @@ class TC_Win32_ClipBoard < Test::Unit::TestCase
54
68
  assert_nothing_raised{ Clipboard.empty }
55
69
  end
56
70
 
71
+ def test_clear_alias
72
+ assert_respond_to(Clipboard, :clear)
73
+ assert_true(Clipboard.method(:clear) == Clipboard.method(:empty))
74
+ end
75
+
57
76
  def test_num_formats
58
77
  assert_respond_to(Clipboard, :num_formats)
59
78
  assert_nothing_raised{ Clipboard.num_formats }
60
79
  assert_kind_of(Fixnum, Clipboard.num_formats)
61
80
  end
62
81
 
63
- # This TypeError check causes a segfault when using Win32API in 1.8.4 or
64
- # earlier.
82
+ def test_num_formats_expected_errors
83
+ assert_raise(ArgumentError){ Clipboard.num_formats(true) }
84
+ end
85
+
65
86
  def test_register_format
66
- assert_respond_to(Clipboard,:register_format)
87
+ assert_respond_to(Clipboard, :register_format)
67
88
  assert_nothing_raised{ Clipboard.register_format('foo') }
68
- #assert_raises(TypeError){ Clipboard.register_format(1) }
89
+ end
90
+
91
+ def test_register_format_expected_errors
92
+ assert_raises(TypeError){ Clipboard.register_format(1) }
69
93
  end
70
94
 
71
95
  def test_formats
@@ -74,21 +98,37 @@ class TC_Win32_ClipBoard < Test::Unit::TestCase
74
98
  assert_kind_of(Hash, Clipboard.formats)
75
99
  end
76
100
 
101
+ def test_formats_expected_errors
102
+ assert_raise(ArgumentError){ Clipboard.formats(true) }
103
+ end
104
+
77
105
  def test_format_available
78
106
  assert_respond_to(Clipboard, :format_available?)
79
107
  assert_nothing_raised{ Clipboard.format_available?(1) }
108
+ assert_boolean(Clipboard.format_available?(1))
80
109
  end
81
110
 
82
111
  def test_format_name
83
112
  assert_respond_to(Clipboard, :format_name)
84
113
  assert_nothing_raised{ Clipboard.format_name(1) }
85
114
  assert_nil(Clipboard.format_name(9999999))
86
- assert_raises(TypeError){ Clipboard.format_name('foo') }
115
+ end
116
+
117
+ def test_format_name_expected_errors
118
+ assert_raise(TypeError){ Clipboard.format_name('foo') }
119
+ end
120
+
121
+ def test_notify_change
122
+ assert_respond_to(Clipboard, :notify_change)
87
123
  end
88
124
 
89
125
  def test_constants
90
126
  assert_not_nil(Clipboard::TEXT)
91
127
  assert_not_nil(Clipboard::OEMTEXT)
92
128
  assert_not_nil(Clipboard::UNICODETEXT)
129
+ assert_not_nil(Clipboard::BITMAP)
130
+ assert_not_nil(Clipboard::DIB)
131
+ assert_not_nil(Clipboard::HDROP)
132
+ assert_not_nil(Clipboard::ENHMETAFILE)
93
133
  end
94
134
  end
@@ -1,27 +1,32 @@
1
1
  require "rubygems"
2
2
 
3
3
  spec = Gem::Specification.new do |gem|
4
- gem.name = "win32-clipboard"
5
- gem.version = "0.4.4"
6
- gem.authors = ["Daniel J. Berger", "Park Heesob"]
7
- gem.email = "djberg96@gmail.com"
8
- gem.homepage = "http://www.rubyforge.org/projects/win32utils"
9
- gem.platform = Gem::Platform::RUBY
10
- gem.summary = "A library for interacting with the Windows clipboard"
11
- gem.description = "A library for interacting with the Windows clipboard"
12
- gem.test_file = "test/test_clipboard.rb"
13
- gem.has_rdoc = true
14
- gem.extra_rdoc_files = ['CHANGES', 'README', 'MANIFEST']
15
- gem.rubyforge_project = "win32utils"
16
- gem.add_dependency("windows-pr", ">= 0.8.1")
17
-
18
- files = Dir["doc/*"] + Dir["examples/*"] + Dir["lib/win32/*"]
19
- files += Dir["test/*"] + Dir["[A-Z]*"]
20
- files.delete_if{ |item| item.include?("CVS") }
21
- gem.files = files
4
+ gem.name = 'win32-clipboard'
5
+ gem.version = '0.5.0'
6
+ gem.authors = ['Daniel J. Berger', 'Park Heesob']
7
+ gem.email = 'djberg96@gmail.com'
8
+ gem.homepage = 'http://www.rubyforge.org/projects/win32utils'
9
+ gem.platform = Gem::Platform::RUBY
10
+ gem.summary = 'A library for interacting with the Windows clipboard'
11
+ gem.test_file = 'test/test_clipboard.rb'
12
+ gem.has_rdoc = true
13
+ gem.extra_rdoc_files = ['CHANGES', 'README', 'MANIFEST']
14
+ gem.rubyforge_project = 'win32utils'
15
+
16
+ gem.add_dependency('windows-pr', '>= 1.0.3')
17
+
18
+ gem.description = "The win32-clipboard library provides an interface for
19
+ interacting with the Windows clipboard. It supports the ability to read
20
+ and write text, images, files, and Windows metafiles.".gsub(/\s+/, ' ')
21
+
22
+ files = Dir['doc/*'] + Dir['examples/*'] + Dir['lib/win32/*']
23
+ files += Dir['test/*'] + Dir['[A-Z]*']
24
+ files.delete_if{ |item| item.include?('CVS') }
25
+
26
+ gem.files = files
22
27
  end
23
28
 
24
29
  if $0 == __FILE__
25
- Gem.manage_gems
30
+ Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
26
31
  Gem::Builder.new(spec).build
27
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win32-clipboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2008-08-26 00:00:00 -06:00
13
+ date: 2009-04-24 00:00:00 -06:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -21,9 +21,9 @@ dependencies:
21
21
  requirements:
22
22
  - - ">="
23
23
  - !ruby/object:Gem::Version
24
- version: 0.8.1
24
+ version: 1.0.3
25
25
  version:
26
- description: A library for interacting with the Windows clipboard
26
+ description: The win32-clipboard library provides an interface for interacting with the Windows clipboard. It supports the ability to read and write text, images, files, and Windows metafiles.
27
27
  email: djberg96@gmail.com
28
28
  executables: []
29
29
 
@@ -38,15 +38,14 @@ files:
38
38
  - lib/win32/clipboard.rb
39
39
  - test/test_clipboard.rb
40
40
  - CHANGES
41
- - examples
42
- - lib
43
41
  - MANIFEST
44
42
  - Rakefile
45
43
  - README
46
- - test
47
44
  - win32-clipboard.gemspec
48
45
  has_rdoc: true
49
46
  homepage: http://www.rubyforge.org/projects/win32utils
47
+ licenses: []
48
+
50
49
  post_install_message:
51
50
  rdoc_options: []
52
51
 
@@ -67,9 +66,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
66
  requirements: []
68
67
 
69
68
  rubyforge_project: win32utils
70
- rubygems_version: 1.2.0
69
+ rubygems_version: 1.3.2
71
70
  signing_key:
72
- specification_version: 2
71
+ specification_version: 3
73
72
  summary: A library for interacting with the Windows clipboard
74
73
  test_files:
75
74
  - test/test_clipboard.rb