ragweed 0.2.0-java

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.
Files changed (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -0
@@ -0,0 +1,583 @@
1
+ require 'ffi'
2
+ require 'ostruct'
3
+ require 'Win32API'
4
+ require 'pp'
5
+
6
+ module Ragweed;end
7
+ module Ragweed::Wrap32
8
+
9
+ NULL = 0x0
10
+
11
+ module PagePerms
12
+ EXECUTE = 0x10
13
+ EXECUTE_READ = 0x20
14
+ EXECUTE_READWRITE = 0x40
15
+ EXECUTE_WRITECOPY = 0x80
16
+ NOACCESS = 0x1
17
+ READONLY = 0x2
18
+ READWRITE = 0x4
19
+ WRITECOPY = 0x8
20
+
21
+ WRITEABLE = [EXECUTE_READWRITE,
22
+ EXECUTE_WRITECOPY,
23
+ READWRITE,
24
+ WRITECOPY]
25
+ end
26
+
27
+ module FileSharing
28
+ NONE = 0
29
+ DELETE = 4
30
+ READ = 1
31
+ WRITE = 2
32
+ end
33
+
34
+ module FileDisposition
35
+ CREATE_ALWAYS = 2
36
+ CREATE_NEW = 1
37
+ OPEN_ALWAYS = 4
38
+ OPEN_EXISTING = 3
39
+ TRUNCATE_EXISTING = 5
40
+ end
41
+
42
+ module FileAttributes
43
+ ARCHIVE = 0x20
44
+ ENCRYPTED = 0x4000
45
+ HIDDEN = 0x2
46
+ NORMAL = 0x80
47
+ OFFLINE = 0x1000
48
+ READONLY = 1
49
+ SYSTEM = 4
50
+ TEMPORARY = 0x100
51
+ BACKUP = 0x02000000
52
+ DELETE_ON_CLOSE = 0x04000000
53
+ NO_BUFFERING = 0x20000000
54
+ NO_RECALL = 0x00100000
55
+ REPARSE_POINT = 0x00200000
56
+ OVERLAPPED = 0x40000000
57
+ POSIX = 0x0100000
58
+ RANDOM_ACCESS = 0x10000000
59
+ SEQUENTIAL = 0x08000000
60
+ WRITE_THROUGH = 0x80000000
61
+ end
62
+
63
+ module FileAccess
64
+ GENERIC_READ = 0x80000000
65
+ GENERIC_WRITE = 0x40000000
66
+ GENERIC_EXECUTE = 0x20000000
67
+ GENERIC_ALL = 0x10000000
68
+ end
69
+
70
+ module FormatArgs
71
+ FROM_SYSTEM = 4096
72
+ ALLOCATE_BUFFER = 256
73
+ end
74
+
75
+ module Win
76
+ extend FFI::Library
77
+
78
+ ffi_lib 'kernel32', 'Advapi32'
79
+ ffi_convention :stdcall
80
+ attach_function 'OpenProcess', [ :long, :long, :long ], :long
81
+ attach_function 'OpenThread', [ :long, :long, :long ], :long
82
+ attach_function 'CloseHandle', [ :long ], :long
83
+ attach_function 'GetLastError', [ ], :long
84
+ attach_function 'FormatMessageA', [ :long, :pointer, :long, :long, :pointer, :long, :pointer ], :void
85
+ attach_function 'VirtualAllocEx', [ :long, :long, :long, :long, :long ], :long
86
+ attach_function 'VirtualFreeEx', [ :long, :long, :long, :long, ], :long
87
+ attach_function 'WriteProcessMemory', [ :long, :long, :pointer, :long, :long ], :long
88
+ attach_function 'ReadProcessMemory', [ :long, :long, :pointer, :long, :long ], :long
89
+ attach_function 'VirtualQueryEx', [ :long, :long, :pointer, :long ], :long
90
+ attach_function 'VirtualProtectEx', [ :long, :long, :long, :long, :pointer ], :void
91
+ attach_function 'GetCurrentProcessId', [], :long
92
+ attach_function 'GetProcessId', [ :long ], :long
93
+ attach_function 'GetCurrentThreadId', [], :long
94
+ attach_function 'GetModuleHandleA', [ :pointer ], :long
95
+ attach_function 'LoadLibraryA', [ :pointer ], :long
96
+ attach_function 'GetProcAddress', [ :long, :pointer], :long
97
+ attach_function 'WaitForSingleObject', [ :long, :long ], :long
98
+ attach_function 'Process32First', [ :long, :pointer ], :long
99
+ attach_function 'Process32Next', [ :long, :pointer ], :long
100
+ attach_function 'Module32First', [ :long, :pointer ], :long
101
+ attach_function 'Module32Next', [ :long, :pointer ], :long
102
+ attach_function 'CreateToolhelp32Snapshot', [ :long, :long ], :long
103
+ attach_function 'Thread32First', [ :long, :pointer ], :long
104
+ attach_function 'Thread32Next', [ :long, :pointer ], :long
105
+ attach_function 'SuspendThread', [ :long ], :long
106
+ attach_function 'ResumeThread', [ :long ], :long
107
+ attach_function 'CreateRemoteThread', [ :long, :long, :long, :long, :long, :long, :long ], :long
108
+ attach_function 'Sleep', [ :long ], :long
109
+ attach_function 'DuplicateHandle', [ :long, :long, :long, :pointer, :long, :long, :long ], :long
110
+ attach_function 'CreateFileA', [ :pointer, :long, :long, :pointer, :long, :long, :pointer ], :long
111
+ attach_function 'OpenEventA', [ :long, :long, :pointer ], :long
112
+ attach_function 'CreateEventA', [ :long, :long, :long, :pointer ], :long
113
+ attach_function 'SetEvent', [ :long ], :long
114
+ attach_function 'ResetEvent', [ :long ], :long
115
+ attach_function 'WriteFile', [ :long, :pointer, :long, :pointer, :pointer ], :long
116
+ attach_function 'ReadFile', [ :long, :pointer, :long, :pointer, :pointer ], :long
117
+ attach_function 'DeviceIoControl', [ :long, :long, :pointer, :long, :pointer, :long, :pointer, :pointer ], :long
118
+ attach_function 'GetOverlappedResult', [ :long, :pointer, :pointer, :long ], :long
119
+ attach_function 'WaitForMultipleObjects', [ :long, :pointer, :long, :long ], :long
120
+ attach_function 'CreateProcessA', [ :pointer, :pointer, :pointer, :pointer, :bool, :long, :pointer, :pointer, :pointer, :pointer ], :long
121
+ attach_function 'CreateProcessW', [ :pointer, :pointer, :pointer, :pointer, :bool, :long, :pointer, :pointer, :pointer, :pointer ], :long
122
+
123
+ ffi_lib 'ntdll'
124
+ ffi_convention :stdcall
125
+ attach_function 'NtQueryInformationProcess', [ :long, :long, :pointer, :long, :pointer ], :long
126
+
127
+ ffi_lib 'msvcrt'
128
+ ffi_convention :stdcall
129
+ attach_function 'malloc', [ :long ], :long
130
+ attach_function 'memcpy', [ :pointer, :pointer, :long ], :long
131
+
132
+ ## XXX This shouldnt be in psapi in win7, need to clean this up
133
+ ## XXX Also the unicode version should be supported, this is NOT complete
134
+ ffi_lib 'psapi'
135
+ ffi_convention :stdcall
136
+ attach_function 'GetMappedFileNameA', [ :long, :long, :pointer, :long ], :long
137
+ end
138
+
139
+ class << self
140
+
141
+ # Get a process handle given a pid
142
+ def open_process(pid)
143
+ r = Win.OpenProcess(0x1F0FFF, 0, pid)
144
+ raise WinX.new(:open_process) if r == 0
145
+ return r
146
+ end
147
+
148
+ # Get a thread handle given a tid; if a block is provided, the semantics are
149
+ # as File#open with a block.
150
+ def open_thread(tid, &block)
151
+ h = Win.OpenThread(0x1F03FF, 0, tid)
152
+ raise WinX.new(:open_thread) if h == 0
153
+ if block_given?
154
+ ret = yield h
155
+ close_handle(h)
156
+ return ret
157
+ end
158
+ h
159
+ end
160
+
161
+ # Close any Win32 handle. Reminder: Win32 handles are just integers, like file
162
+ # descriptors in Posix.
163
+ def close_handle(h)
164
+ raise WinX.new(:close_handle) if Win.CloseHandle(h) == 0
165
+ end
166
+
167
+ # Get the last error code (errno) (can't fail)
168
+ def get_last_error
169
+ Win.GetLastError()
170
+ end
171
+
172
+ # strerror(errno) (can't fail)
173
+ def format_message(code=nil)
174
+ code ||= get_last_error
175
+ buf = FFI::MemoryPointer.from_string("\x00" * 4096)
176
+ Win.FormatMessageA(4096, nil, code, 0x00000400, buf, 4096, nil)
177
+ return buf.to_s.split("\x00")[0]
178
+ end
179
+
180
+ # Allocate memory in a remote process (or yourself, with handle -1)
181
+ def virtual_alloc_ex(h, sz, addr=NULL, prot=0x40)
182
+ r = Win.VirtualAllocEx(h, addr, sz, 0x1000, prot)
183
+ raise WinX.new(:virtual_alloc_ex) if r == 0
184
+ return r
185
+ end
186
+
187
+ # Free memory in a remote process given the pointer returned from virtual_alloc_ex
188
+ def virtual_free_ex(h, ptr, type=0x8000)
189
+ r = Win.VirtualFreeEx(h, ptr.to_i, 0, type)
190
+ raise WinX.new(:virtual_free_ex) if r == 0
191
+ return r
192
+ end
193
+
194
+ # Write a string into the memory of a remote process given its handle and an address
195
+ def write_process_memory(h, dst, val)
196
+ val = val.to_s if not val.kind_of? String
197
+ r = Win.WriteProcessMemory(h, dst.to_i, val, val.size, NULL)
198
+ raise WinX.new(:write_process_memory) if r == 0
199
+ return r
200
+ end
201
+
202
+ # Read from a remote process given an address and length, returning a string.
203
+ def read_process_memory(h, ptr, len)
204
+ # val = FFI::MemoryPointer.from_string("\x00" * len)
205
+ val = "\x00" * len
206
+ r = Win.ReadProcessMemory(h, ptr.to_i, val, len, NULL)
207
+ raise WinX.new(:read_process_memory) if r == 0
208
+ return val ## don't handle short reads XXX
209
+ end
210
+
211
+ def get_mapped_filename(h, lpv, size)
212
+ val = "\x00" * size
213
+ r = Win.GetMappedFileNameA(h, lpv.to_i, val, size)
214
+ raise WinX.new(:get_mapped_filename) if r == 0
215
+ return val
216
+ end
217
+
218
+ def str2memory_basic_info(mbi)
219
+ s = OpenStruct.new
220
+ s.BaseAddress,
221
+ s.AllocationBase,
222
+ s.AllocationProtect,
223
+ s.RegionSize,
224
+ s.State,
225
+ s.Protect,
226
+ s.Type = mbi.unpack("LLLLLLL")
227
+ return s
228
+ end
229
+
230
+ # Return a struct with the MEMORY_BASIC_INFORMATION for a given address in the
231
+ # memory of a remote process. Gives you addressable memory ranges and protection
232
+ # flags.
233
+ def virtual_query_ex(h, ptr)
234
+ mbi = [0,0,0,0,0,0,0].pack("LLLLLLL")
235
+ if Win.VirtualQueryEx(h, ptr, mbi, mbi.size)
236
+ str2memory_basic_info(mbi)
237
+ else
238
+ nil
239
+ end
240
+ end
241
+
242
+ # Change the protection of specific memory regions in a remote process.
243
+ def virtual_protect_ex(h, addr, prot, size=0)
244
+ old = [0].pack("L")
245
+ base = virtual_query_ex(h, addr).BaseAddress if size == 0
246
+ base ||= addr
247
+
248
+ if Win.VirtualProtectEx(h, base, size, prot, old)
249
+ old.unpack("L").first
250
+ else
251
+ raise WinX.new(:virtual_protect_ex)
252
+ end
253
+ end
254
+
255
+ # getpid
256
+ def get_current_process_id
257
+ Win.GetCurrentProcessId() # can't realistically fail
258
+ end
259
+
260
+ # get_processid
261
+ def get_process_id(h)
262
+ Win.GetProcessId(h)
263
+ end
264
+
265
+ # gettid
266
+ def get_current_thread_id
267
+ Win.GetCurrentThreadId() # can't realistically fail
268
+ end
269
+
270
+ # Given a DLL name, get a handle to the DLL.
271
+ def get_module_handle(name)
272
+ name = name
273
+ r = Win.GetModuleHandleA(name)
274
+ raise WinX.new(:get_module_handle) if r == 0
275
+ return r
276
+ end
277
+
278
+ # load a library explicitly from a dll
279
+ def load_library(name)
280
+ name = name
281
+ r = Win.LoadLibraryA(name)
282
+ raise WinX.new(:load_library) if r == 0
283
+ return r
284
+ end
285
+
286
+ # Using notation x = "foo!bar" or x = handle, y = meth, look up a function's
287
+ # address in a module. Note that this is local, not remote.
288
+ def get_proc_address(x, y=nil)
289
+ if not y
290
+ mod, meth = x.split "!"
291
+ h = get_module_handle(mod)
292
+ else
293
+ h = x
294
+ meth = y
295
+ end
296
+
297
+ r = Win.GetProcAddress(h, meth)
298
+ return r # pass error through
299
+ end
300
+
301
+ # Select(2), for a single object handle.
302
+ def wait_for_single_object(h)
303
+ r = Win.WaitForSingleObject(h, -1)
304
+ raise WinX.new(:wait_for_single_object) if r == -1
305
+ end
306
+
307
+ def str2process_info(str)
308
+ ret = OpenStruct.new
309
+ ret.dwSize,
310
+ ret.cntUsage,
311
+ ret.th32ProcessID,
312
+ ret.th32DefaultHeapID,
313
+ ret.th32ModuleID,
314
+ ret.cntThreads,
315
+ ret.th32ParentProcessID,
316
+ ret.pcPriClassBase,
317
+ ret.dwFlags,
318
+ ret.szExeFile = str.unpack("LLLLLLLLLA2048")
319
+ ret.szExeFile = ret.szExeFile.asciiz
320
+ return ret
321
+ end
322
+
323
+ # Use Toolhelp32 to enumerate all running processes on the box, returning
324
+ # a struct with PIDs and executable names.
325
+ def all_processes
326
+ h = Win.CreateToolhelp32Snapshot(0x2, 0)
327
+ if h != -1
328
+ pi = [(9*4)+2048,0,0,0,0,0,0,0,0,"\x00"*2048].pack("LLLLLLLLLa2048")
329
+ if Win.Process32First(h, pi) != 0
330
+ yield str2process_info(pi)
331
+ while Win.Process32Next(h, pi) != 0
332
+ yield str2process_info(pi)
333
+ end
334
+ end
335
+ else
336
+ raise WinX.new(:create_toolhelp32_snapshot)
337
+ end
338
+ end
339
+
340
+ def str2module_info(str)
341
+ ret = OpenStruct.new
342
+ ret.dwSize,
343
+ ret.th32ModuleID,
344
+ ret.th32ProcessID,
345
+ ret.GlblcntUsage,
346
+ ret.ProccntUsage,
347
+ ret.modBaseAddr,
348
+ ret.modBaseSize,
349
+ ret.hModule,
350
+ ret.szModule,
351
+ ret.szExePath = str.unpack("LLLLLLLLA256A260")
352
+ ret.szModule = ret.szModule.asciiz
353
+ ret.szExePath = ret.szExePath.asciiz
354
+ return ret
355
+ end
356
+
357
+ # Given a pid, enumerate the modules loaded into the process, returning base
358
+ # addresses, memory ranges, and the module name.
359
+ def list_modules(pid=0)
360
+ h = Win.CreateToolhelp32Snapshot(0x8, pid)
361
+ if h != -1
362
+ mi = [260+256+(8*4),0,0,0,0,0,0,0,"\x00"*256,"\x00"*260].pack("LLLLLLLLa256a260")
363
+ if Win.Module32First(h, mi) != 0
364
+ yield str2module_info(mi)
365
+ while Win.Module32Next(h, mi) != 0
366
+ yield str2module_info(mi)
367
+ end
368
+ end
369
+ else
370
+ raise WinX.new(:create_toolhelp32_snapshot)
371
+ end
372
+ end
373
+
374
+ # Use virtual_query_ex to tell whether an address is writable.
375
+ def writeable?(h, off)
376
+ if (x = virtual_query_ex(h, off))
377
+ return PagePerms::WRITEABLE.member?(x.Protect & 0xFF)
378
+ else
379
+ return false
380
+ end
381
+ end
382
+
383
+ # NQIP does a lot of things, the most useful of which are getting the
384
+ # image name of a running process, and telling whether a debugger is loaded. This
385
+ # interface is Ioctl-style; provide an ordinal and a buffer to pass results through.
386
+ def nt_query_information_process(h, ord, buf)
387
+ lenp = [0].pack("L")
388
+ if Win.NtQueryInformationProcess(h, ord, buf, buf.size, lenp) == 0
389
+ len = lenp.unpack("L").first
390
+ return buf[0..(len-1)]
391
+ end
392
+ nil
393
+ end
394
+
395
+ def str2thread_info(str)
396
+ ret = OpenStruct.new
397
+ ret.dwSize,
398
+ ret.cntUsage,
399
+ ret.th32ThreadID,
400
+ ret.th32OwnerProcessID,
401
+ ret.tpBasePri,
402
+ ret.tpDeltaPri,
403
+ ret.thFlags = str.unpack("LLLLLLL")
404
+ return ret
405
+ end
406
+
407
+ # List all the threads in a process given its pid, returning a struct containing
408
+ # tids and run state. This is relatively expensive, because it uses Toolhelp32.
409
+ def threads(pid)
410
+ h = Win.CreateToolhelp32Snapshot(0x4, pid)
411
+ if h != -1
412
+ mi = [(7*4),0,0,0,0,0,0].pack("LLLLLLL")
413
+ if Win.Thread32First(h, mi) != 0
414
+ ti = str2thread_info(mi)
415
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
416
+ while Win.Thread32Next(h, mi) != 0
417
+ ti = str2thread_info(mi)
418
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
419
+ end
420
+ end
421
+ else
422
+ raise WinX.new(:create_toolhelp32_snapshot)
423
+ end
424
+ end
425
+
426
+ # Suspend a thread given its handle.
427
+ def suspend_thread(h)
428
+ r = Win.SuspendThread(h)
429
+ raise WinX.new(:suspend_thread) if r == 0
430
+ return r
431
+ end
432
+
433
+ # Resume a suspended thread, returning nonzero if the thread was suspended,
434
+ # and 0 if it was running.
435
+ def resume_thread(h)
436
+ ResumeThread(h)
437
+ end
438
+
439
+ # Create a remote thread in the process, starting at the location
440
+ # "start", with the threadproc argument "arg"
441
+ def create_remote_thread(h, start, arg)
442
+ r = Win.CreateRemoteThread(h, NULL, 0, start.to_i, arg.to_i, 0, 0)
443
+ raise WinX.new(:create_remote_thread) if r == 0
444
+ return r
445
+ end
446
+
447
+ def sleep(ms=0)
448
+ Win.Sleep(ms)
449
+ end
450
+
451
+ # clone a handle out of another open process (or self, with -1)
452
+ def duplicate_handle(ph, h)
453
+ ret = "\x00\x00\x00\x00"
454
+ r = Win.DuplicateHandle(ph, h, -1, ret, 0, 0, 0x2)
455
+ raise WinX.new(:duplicate_handle) if r == 0
456
+ ret.to_l32
457
+ end
458
+
459
+ def create_file(name, opts={})
460
+ opts[:disposition] ||= FileDisposition::OPEN_ALWAYS
461
+ opts[:sharing] ||= FileSharing::READ | FileSharing::WRITE
462
+ opts[:access] ||= FileAccess::GENERIC_ALL
463
+ opts[:flags] ||= 0
464
+
465
+ r = Win.CreateFileA(name, opts[:access], opts[:sharing], NULL, opts[:disposition], opts[:flags], NULL)
466
+ raise WinX.new(:create_file) if r == -1
467
+ return r
468
+ end
469
+
470
+ # i haven't made this work, but named handles are kind of silly anyways
471
+ def open_event(name)
472
+ r = Win.OpenEventA(0, 0, name)
473
+ raise WinX.new(:open_event) if r == 0
474
+ return r
475
+ end
476
+
477
+ # signal an event
478
+ def set_event(h)
479
+ r = Win.SetEvent(h)
480
+ raise WinX.new(:set_event) if r == 0
481
+ return r
482
+ end
483
+
484
+ # force-unsignal event (waiting on the event handle also does this)
485
+ def reset_event(h)
486
+ r = Win.ResetEvent(h)
487
+ raise WinX.new(:reset_event) if r == 0
488
+ return r
489
+ end
490
+
491
+ # create an event, which you can signal and wait on across processes
492
+ def create_event(name=nil, auto=false, signalled=false)
493
+ auto = (1 if auto) || 0
494
+ signalled = (1 if signalled) || 0
495
+ name ||= 0
496
+
497
+ r = Win.CreateEventA(0, auto, signalled, name);
498
+ raise WinX.new(:create_event) if r == 0
499
+ return r
500
+ end
501
+
502
+ def write_file(h, buf, overlapped=nil)
503
+ if overlapped
504
+ opp = overlapped.to_s
505
+ else
506
+ opp = NULL
507
+ end
508
+
509
+ outw = "\x00" * 4
510
+ r = Win.WriteFile(h, buf, buf.size, outw, opp)
511
+ raise WinX.new(:write_file) if r == 0 and get_last_error != 997
512
+ return buf, outw.unpack("L").first
513
+ end
514
+
515
+ def read_file(h, count, overlapped=nil)
516
+ if overlapped
517
+ opp = overlapped.to_s
518
+ else
519
+ opp = NULL
520
+ end
521
+ outw = "\x00" * 4
522
+ if not (buf = overlapped.try(:target)) or buf.size < count
523
+ buf = "\x00" * count
524
+ overlapped.target = buf if overlapped
525
+ end
526
+
527
+ r = Win.ReadFile(h, buf, count, outw, opp)
528
+ raise WinX.new(:read_file) if r == 0 and get_last_error != 997
529
+ return buf, outw.unpack("L").first
530
+ end
531
+
532
+ def device_io_control(h, code, inbuf, outbuf, overlapped=NULL)
533
+ overlapped = overlapped.to_s if overlapped
534
+ outw = "\x00" * 4
535
+ r = Win.DeviceIoControl(h, code, inbuf, inbuf.size, outbuf, outbuf.size, outw, overlapped)
536
+ raise WinX.new(:device_io_control) if r == 0 and get_last_error != 997
537
+ return outw.unpack("L").first
538
+ end
539
+
540
+ def get_overlapped_result(h, overlapped)
541
+ overlapped = overlapped.to_s
542
+ outw = "\x00" * 4
543
+ r = Win.GetOverlappedResult(h, overlapped, outw, 0)
544
+ raise WinX.new(:get_overlapped_result) if r == 0
545
+ return outw.unpack("L").first
546
+ end
547
+
548
+ # just grab some local memory
549
+ # XXX same as FFI name ?
550
+ def malloc(sz)
551
+ r = Win.malloc(sz)
552
+ raise WinX.new(:malloc) if r == 0
553
+ return r
554
+ end
555
+
556
+ def memcpy(dst, src, size)
557
+ Win.memcpy(dst, src, size)
558
+ end
559
+
560
+ # Block wrapper for thread suspension
561
+ def with_suspended_thread(tid)
562
+ open_thread(tid) do |h|
563
+ begin
564
+ suspend_thread(h)
565
+ ret = yield h
566
+ ensure
567
+ resume_thread(h)
568
+ end
569
+ end
570
+ end
571
+
572
+ def wfmo(handles, ms=100)
573
+ hp = handles.to_ptr
574
+ r = Win.WaitForMultipleObjects(handles.size, hp, 0, ms)
575
+ raise WinX(:wait_for_multiple_objects) if r == 0xFFFFFFFF
576
+ if r < handles.size
577
+ return handles[r]
578
+ else
579
+ return nil
580
+ end
581
+ end
582
+ end
583
+ end
@@ -0,0 +1,59 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/wrap32/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Wrap32
6
+
7
+ # :stopdoc:
8
+ VERSION = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION"))
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility function to load utility classes and extensions
36
+ def self.require_utils
37
+ %w{utils}.each{|r| require self.libpath(r)+'.rb'}
38
+ end
39
+
40
+ # Utility method used to require all files ending in .rb that lie in the
41
+ # directory below this file that has the same name as the filename passed
42
+ # in. Optionally, a specific _directory_ name can be passed in such that
43
+ # the _filename_ does not have to be equivalent to the directory.
44
+ #
45
+ def self.require_all_libs_relative_to( fname, dir = nil )
46
+ self.require_utils
47
+ dir ||= ::File.basename(fname, '.*')
48
+ search_me = ::File.expand_path(
49
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
50
+
51
+ Dir.glob(search_me).sort.each {|rb| require rb}
52
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
53
+
54
+ end
55
+ end # module Ragweed::Wrap32
56
+
57
+ Ragweed::Wrap32.require_all_libs_relative_to(__FILE__)
58
+
59
+ # EOF