win32-clipboard 0.5.2 → 0.6.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.
- checksums.yaml +7 -0
- data/CHANGES +91 -81
- data/MANIFEST +12 -8
- data/README +112 -112
- data/Rakefile +40 -15
- data/examples/clipboard_test.rb +28 -28
- data/lib/win32/clipboard.rb +414 -412
- data/lib/win32/html_clipboard.rb +232 -0
- data/lib/win32/windows/constants.rb +10 -0
- data/lib/win32/windows/functions.rb +56 -0
- data/lib/win32/windows/structs.rb +43 -0
- data/test/test_clipboard.rb +155 -135
- data/test/test_html_clipboard.rb +50 -0
- data/win32-clipboard.gemspec +26 -30
- metadata +78 -46
data/examples/clipboard_test.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
##########################################################################
|
2
|
-
# clipboard_test.rb (win32-clipboard)
|
3
|
-
#
|
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
|
-
##########################################################################
|
7
|
-
require "win32/clipboard"
|
8
|
-
require "pp"
|
9
|
-
include Win32
|
10
|
-
|
11
|
-
puts "VERSION: " + Clipboard::VERSION
|
12
|
-
|
13
|
-
pp Clipboard.formats
|
14
|
-
pp Clipboard.data(Clipboard::UNICODETEXT)
|
15
|
-
pp Clipboard.format_available?(49161)
|
16
|
-
pp Clipboard.format_name(999999999)
|
17
|
-
pp Clipboard.format_available?(9999999)
|
18
|
-
|
19
|
-
puts "Data was: [" + Clipboard.data + "]"
|
20
|
-
|
21
|
-
Clipboard.set_data("foobar")
|
22
|
-
|
23
|
-
puts "Data is now: [" + Clipboard.data + "]"
|
24
|
-
|
25
|
-
puts "Number of available formats: " + Clipboard.num_formats.to_s
|
26
|
-
|
27
|
-
Clipboard.empty
|
28
|
-
|
1
|
+
##########################################################################
|
2
|
+
# clipboard_test.rb (win32-clipboard)
|
3
|
+
#
|
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
|
+
##########################################################################
|
7
|
+
require "win32/clipboard"
|
8
|
+
require "pp"
|
9
|
+
include Win32
|
10
|
+
|
11
|
+
puts "VERSION: " + Clipboard::VERSION
|
12
|
+
|
13
|
+
pp Clipboard.formats
|
14
|
+
pp Clipboard.data(Clipboard::UNICODETEXT)
|
15
|
+
pp Clipboard.format_available?(49161)
|
16
|
+
pp Clipboard.format_name(999999999)
|
17
|
+
pp Clipboard.format_available?(9999999)
|
18
|
+
|
19
|
+
puts "Data was: [" + Clipboard.data + "]"
|
20
|
+
|
21
|
+
Clipboard.set_data("foobar")
|
22
|
+
|
23
|
+
puts "Data is now: [" + Clipboard.data + "]"
|
24
|
+
|
25
|
+
puts "Number of available formats: " + Clipboard.num_formats.to_s
|
26
|
+
|
27
|
+
Clipboard.empty
|
28
|
+
|
29
29
|
puts "Clipboard emptied"
|
data/lib/win32/clipboard.rb
CHANGED
@@ -1,412 +1,414 @@
|
|
1
|
-
require 'windows
|
2
|
-
require 'windows
|
3
|
-
require 'windows
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
end
|
1
|
+
require File.join(File.dirname(__FILE__), 'windows', 'constants')
|
2
|
+
require File.join(File.dirname(__FILE__), 'windows', 'structs')
|
3
|
+
require File.join(File.dirname(__FILE__), 'windows', 'functions')
|
4
|
+
|
5
|
+
# The Win32 module serves as a namespace only.
|
6
|
+
module Win32
|
7
|
+
|
8
|
+
# The Clipboard class encapsulates functions that relate to the MS Windows clipboard.
|
9
|
+
class Clipboard
|
10
|
+
|
11
|
+
include Windows::Constants
|
12
|
+
include Windows::Structs
|
13
|
+
include Windows::Functions
|
14
|
+
|
15
|
+
extend Windows::Functions
|
16
|
+
extend Windows::Structs
|
17
|
+
|
18
|
+
# The version of this library
|
19
|
+
VERSION = '0.6.0'
|
20
|
+
|
21
|
+
# Clipboard formats
|
22
|
+
|
23
|
+
# Text
|
24
|
+
|
25
|
+
TEXT = 1
|
26
|
+
OEMTEXT = 7
|
27
|
+
UNICODETEXT = 13
|
28
|
+
|
29
|
+
# Images
|
30
|
+
|
31
|
+
DIB = 8
|
32
|
+
BITMAP = 2
|
33
|
+
|
34
|
+
# Metafiles
|
35
|
+
|
36
|
+
ENHMETAFILE = 14
|
37
|
+
|
38
|
+
# Files
|
39
|
+
|
40
|
+
HDROP = 15
|
41
|
+
|
42
|
+
# Empties the contents of the clipboard.
|
43
|
+
#
|
44
|
+
def self.empty
|
45
|
+
begin
|
46
|
+
open
|
47
|
+
unless EmptyClipboard()
|
48
|
+
raise SystemCallError.new('EmptyClipboard', FFI.errno)
|
49
|
+
end
|
50
|
+
ensure
|
51
|
+
close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
alias clear empty
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the number of different data formats currently on the clipboard.
|
60
|
+
#
|
61
|
+
def self.num_formats
|
62
|
+
CountClipboardFormats() || 0
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns whether or not +format+ (an integer) is currently available.
|
66
|
+
#
|
67
|
+
def self.format_available?(format)
|
68
|
+
IsClipboardFormatAvailable(format)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the data currently in the clipboard. If +format+ is
|
72
|
+
# specified, it will attempt to retrieve the data in that format. The
|
73
|
+
# default is Clipboard::TEXT.
|
74
|
+
#
|
75
|
+
# If there is no data in the clipboard, or data is available but the
|
76
|
+
# format doesn't match the data, then an empty string is returned.
|
77
|
+
#
|
78
|
+
# Examples:
|
79
|
+
#
|
80
|
+
# # Get some plain text
|
81
|
+
# Win32::Clipboard.data # => e.g. 'hello'
|
82
|
+
#
|
83
|
+
# # Get a list of files copied from the Windows Explorer window
|
84
|
+
# Win32::Clipboard.data(Clipboard::HDROP) # => ['foo.rb', 'bar.rb']
|
85
|
+
#
|
86
|
+
# # Get a bitmap and write it to another file
|
87
|
+
# File.open('bitmap_copy', 'wb'){ |fh|
|
88
|
+
# fh.write Win32::Clipboard.data(Clipboard::DIB)
|
89
|
+
# }
|
90
|
+
#
|
91
|
+
def self.data(format = TEXT)
|
92
|
+
begin
|
93
|
+
open
|
94
|
+
|
95
|
+
if IsClipboardFormatAvailable(format)
|
96
|
+
handle = GetClipboardData(format)
|
97
|
+
|
98
|
+
case format
|
99
|
+
when UNICODETEXT
|
100
|
+
size = GlobalSize(handle)
|
101
|
+
ptr = GlobalLock(handle)
|
102
|
+
clip_data = ptr.read_bytes(size).force_encoding('UTF-16LE').encode('UTF-8').strip
|
103
|
+
when TEXT, OEMTEXT
|
104
|
+
size = GlobalSize(handle)
|
105
|
+
ptr = GlobalLock(handle)
|
106
|
+
|
107
|
+
clip_data = ptr.read_bytes(size).strip
|
108
|
+
|
109
|
+
unless clip_data.ascii_only?
|
110
|
+
clip_data.force_encoding('BINARY')
|
111
|
+
end
|
112
|
+
when HDROP
|
113
|
+
clip_data = get_file_list(handle)
|
114
|
+
when ENHMETAFILE
|
115
|
+
clip_data = get_metafile_data(handle)
|
116
|
+
when DIB, BITMAP
|
117
|
+
clip_data = get_image_data(handle)
|
118
|
+
else
|
119
|
+
raise "format '#{format}' not supported"
|
120
|
+
end
|
121
|
+
else
|
122
|
+
clip_data = ''
|
123
|
+
end
|
124
|
+
ensure
|
125
|
+
close
|
126
|
+
end
|
127
|
+
|
128
|
+
clip_data
|
129
|
+
end
|
130
|
+
|
131
|
+
class << self
|
132
|
+
alias get_data data
|
133
|
+
end
|
134
|
+
|
135
|
+
# Sets the clipboard contents to the data that you specify. You may
|
136
|
+
# optionally specify a clipboard format. The default is Clipboard::TEXT.
|
137
|
+
#
|
138
|
+
# Example:
|
139
|
+
#
|
140
|
+
# # Put the string 'hello' on the clipboard
|
141
|
+
# Win32::Clipboard.set_data('hello')
|
142
|
+
#
|
143
|
+
# # Put the image test.bmp on the clipboard
|
144
|
+
# f = File.open("test.bmp", "rb")
|
145
|
+
# str = f.read
|
146
|
+
# Clipboard.set_data(str, Win32::Clipboard::DIB)
|
147
|
+
#
|
148
|
+
def self.set_data(clip_data, format = TEXT)
|
149
|
+
begin
|
150
|
+
clear
|
151
|
+
open
|
152
|
+
|
153
|
+
# NULL terminate text or strip header of bitmap file
|
154
|
+
case format
|
155
|
+
when UNICODETEXT
|
156
|
+
clip_data.encode!('UTF-16LE')
|
157
|
+
clip_data << "\0".encode('UTF-16LE')
|
158
|
+
buf = clip_data
|
159
|
+
extra = 4
|
160
|
+
when TEXT, OEMTEXT
|
161
|
+
clip_data << "\0"
|
162
|
+
buf = clip_data
|
163
|
+
extra = 4
|
164
|
+
when BITMAP, DIB
|
165
|
+
buf = clip_data[14..clip_data.length] # sizeof(BITMAPFILEHEADER) = 14
|
166
|
+
extra = 0
|
167
|
+
end
|
168
|
+
|
169
|
+
# Global Allocate a movable piece of memory.
|
170
|
+
hmem = GlobalAlloc(GHND, buf.bytesize + extra)
|
171
|
+
mptr = GlobalLock(hmem)
|
172
|
+
|
173
|
+
mptr.write_bytes(buf, 0, buf.bytesize)
|
174
|
+
|
175
|
+
# Set the new data
|
176
|
+
if SetClipboardData(format, hmem) == 0
|
177
|
+
raise SystemCallError.new('SetClipboardData', FFI.errno)
|
178
|
+
end
|
179
|
+
ensure
|
180
|
+
GlobalFree(hmem)
|
181
|
+
close
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns a hash of all the current formats, with the format number as
|
186
|
+
# the key and the format name as the value for that key.
|
187
|
+
#
|
188
|
+
# Example:
|
189
|
+
#
|
190
|
+
# Win32::Clipboard.formats # => {1 => nil, 49335 => "HTML Format"}
|
191
|
+
#
|
192
|
+
def self.formats
|
193
|
+
formats = {}
|
194
|
+
format = 0
|
195
|
+
|
196
|
+
begin
|
197
|
+
self.open
|
198
|
+
while 0 != (format = EnumClipboardFormats(format))
|
199
|
+
buf = FFI::MemoryPointer.new(:char, 80)
|
200
|
+
GetClipboardFormatName(format, buf, buf.size)
|
201
|
+
string = buf.read_string
|
202
|
+
formats[format] = string.empty? ? nil : string
|
203
|
+
end
|
204
|
+
ensure
|
205
|
+
self.close
|
206
|
+
end
|
207
|
+
|
208
|
+
formats
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns the corresponding name for the given +format_num+, or nil
|
212
|
+
# if it does not exist. You cannot specify any of the predefined
|
213
|
+
# clipboard formats (or nil is returned), only registered formats.
|
214
|
+
#
|
215
|
+
def self.format_name(format_num)
|
216
|
+
val = nil
|
217
|
+
buf = FFI::MemoryPointer.new(:char, 80)
|
218
|
+
|
219
|
+
begin
|
220
|
+
open
|
221
|
+
|
222
|
+
if GetClipboardFormatName(format_num, buf, buf.size) != 0
|
223
|
+
val = buf.read_string
|
224
|
+
end
|
225
|
+
ensure
|
226
|
+
close
|
227
|
+
end
|
228
|
+
|
229
|
+
val
|
230
|
+
end
|
231
|
+
|
232
|
+
# Registers the given +format+ (a String) as a clipboard format, which
|
233
|
+
# can then be used as a valid clipboard format. Returns the integer
|
234
|
+
# value of the registered format.
|
235
|
+
#
|
236
|
+
# If a registered format with the specified name already exists, a new
|
237
|
+
# format is not registered and the return value identifies the existing
|
238
|
+
# format. This enables more than one application to copy and paste data
|
239
|
+
# using the same registered clipboard format. Note that the format name
|
240
|
+
# comparison is case-insensitive.
|
241
|
+
#
|
242
|
+
# Registered clipboard formats are identified by values in the range 0xC000
|
243
|
+
# through 0xFFFF.
|
244
|
+
#
|
245
|
+
def self.register_format(format)
|
246
|
+
format_value = RegisterClipboardFormat(format)
|
247
|
+
|
248
|
+
if format_value == 0
|
249
|
+
raise SystemCallError.new('RegisterClipboardFormat', FFI.errno)
|
250
|
+
end
|
251
|
+
|
252
|
+
format_value
|
253
|
+
end
|
254
|
+
|
255
|
+
# Sets up a notification loop that will call the provided block whenever
|
256
|
+
# there's a change to the clipboard.
|
257
|
+
#
|
258
|
+
# Example:
|
259
|
+
#
|
260
|
+
# Win32::Clipboard.notify_change{
|
261
|
+
# puts "There's been a change in the clipboard contents!"
|
262
|
+
# }
|
263
|
+
#--
|
264
|
+
# We skip the first notification because the very act of attaching the
|
265
|
+
# new window causes it to trigger once.
|
266
|
+
#
|
267
|
+
def self.notify_change(&block)
|
268
|
+
name = 'ruby-clipboard-' + Time.now.to_s
|
269
|
+
handle = CreateWindowEx(0, 'static', name, 0, 0, 0, 0, 0, 0, 0, 0, nil)
|
270
|
+
|
271
|
+
@first_notify = true
|
272
|
+
|
273
|
+
wnd_proc = FFI::Function.new(:uintptr_t, [:uintptr_t, :uint, :uintptr_t, :uintptr_t]) do |hwnd, umsg, wparam, lparam|
|
274
|
+
case umsg
|
275
|
+
when WM_DRAWCLIPBOARD
|
276
|
+
yield unless @first_notify
|
277
|
+
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
278
|
+
if next_viewer != 0
|
279
|
+
PostMessage(next_viewer, umsg, wparam, lparam)
|
280
|
+
end
|
281
|
+
rv = 0
|
282
|
+
when WM_CHANGECBCHAIN
|
283
|
+
yield unless @first_notify
|
284
|
+
next_viewer = lparam if next_viewer == wparam
|
285
|
+
if next_viewer != 0
|
286
|
+
PostMessage(next_viewer, umsg, wparam, lparam)
|
287
|
+
end
|
288
|
+
rv = 0
|
289
|
+
else
|
290
|
+
rv = DefWindowProc(hwnd, umsg, wparam, lparam)
|
291
|
+
end
|
292
|
+
|
293
|
+
@first_notify = false
|
294
|
+
|
295
|
+
rv
|
296
|
+
end
|
297
|
+
|
298
|
+
if SetWindowLongPtr(handle, GWL_WNDPROC, wnd_proc.address) == 0
|
299
|
+
raise SystemCallError.new('SetWindowLongPtr', FFI.errno)
|
300
|
+
end
|
301
|
+
|
302
|
+
next_viewer = SetClipboardViewer(handle)
|
303
|
+
|
304
|
+
if next_viewer.nil?
|
305
|
+
raise SystemCallError.new('SetClipboardViewer', FFI.errno)
|
306
|
+
end
|
307
|
+
|
308
|
+
SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
|
309
|
+
|
310
|
+
msg = FFI::MemoryPointer.new(:char, 100)
|
311
|
+
|
312
|
+
while true
|
313
|
+
while PeekMessage(msg, handle, 0, 0, 1)
|
314
|
+
TranslateMessage(msg)
|
315
|
+
DispatchMessage(msg)
|
316
|
+
end
|
317
|
+
sleep 0.1
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
private
|
322
|
+
|
323
|
+
# Opens the clipboard and prevents other applications from modifying
|
324
|
+
# the clipboard content until it is closed.
|
325
|
+
#
|
326
|
+
def self.open
|
327
|
+
unless OpenClipboard(0)
|
328
|
+
raise SystemCallError.new('OpenClipboard', FFI.errno)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
# Close the clipboard
|
333
|
+
#
|
334
|
+
def self.close
|
335
|
+
unless CloseClipboard()
|
336
|
+
raise SystemCallError.new('CloseClipboard', FFI.errno)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
# Get data for enhanced metadata files
|
341
|
+
#
|
342
|
+
def self.get_metafile_data(handle)
|
343
|
+
buf_size = GetEnhMetaFileBits(handle, 0, nil)
|
344
|
+
buf = FFI::MemoryPointer.new(:char, buf_size)
|
345
|
+
GetEnhMetaFileBits(handle, buf.size, buf)
|
346
|
+
buf.read_string
|
347
|
+
end
|
348
|
+
|
349
|
+
# Get data for bitmap files
|
350
|
+
#
|
351
|
+
def self.get_image_data(handle)
|
352
|
+
buf = nil
|
353
|
+
|
354
|
+
begin
|
355
|
+
ptr = GlobalLock(handle)
|
356
|
+
buf_size = GlobalSize(handle)
|
357
|
+
|
358
|
+
bmi = BITMAPINFO.new(ptr)
|
359
|
+
|
360
|
+
size_image = bmi[:bmiHeader][:biSizeImage]
|
361
|
+
size_image = buf_size + 16 if size_image == 0
|
362
|
+
|
363
|
+
# Calculate the header size
|
364
|
+
case bmi[:bmiHeader][:biBitCount]
|
365
|
+
when 1
|
366
|
+
table_size = 2
|
367
|
+
when 4
|
368
|
+
table_size = 16
|
369
|
+
when 8
|
370
|
+
table_size = 256
|
371
|
+
when 16, 32
|
372
|
+
if bmi[:bmiHeader][:biCompression] == 0
|
373
|
+
table_size = bmi[:bmiHeader][:biClrUsed]
|
374
|
+
elsif compression == 3
|
375
|
+
table_size = 3
|
376
|
+
else
|
377
|
+
raise "invalid bit/compression combination"
|
378
|
+
end
|
379
|
+
when 24
|
380
|
+
table_size = bmi[:bmiHeader][:biClrUsed]
|
381
|
+
else
|
382
|
+
raise "invalid bit count"
|
383
|
+
end # case
|
384
|
+
|
385
|
+
# TODO: Document what's happening here.
|
386
|
+
offset = 0x36 + (table_size * 4)
|
387
|
+
|
388
|
+
buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + ptr.read_bytes(buf_size)
|
389
|
+
ensure
|
390
|
+
GlobalUnlock(handle) if 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 = DragQueryFileA(handle, 0xFFFFFFFF, nil, 0)
|
401
|
+
|
402
|
+
0.upto(count - 1){ |i|
|
403
|
+
length = DragQueryFileA(handle, i, nil, 0) + 1
|
404
|
+
buf = FFI::MemoryPointer.new(:char, length)
|
405
|
+
DragQueryFileA(handle, i, buf, buf.size)
|
406
|
+
array << buf.read_string
|
407
|
+
}
|
408
|
+
|
409
|
+
array
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
require File.join(File.dirname(__FILE__), 'html_clipboard')
|