exerb 6.0.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/.gitignore +8 -0
- data/ChangeLog.ja.rd +305 -0
- data/README.en.txt +12 -0
- data/README.ja.html +143 -0
- data/README.ja.txt +6 -0
- data/README.md +50 -0
- data/Rakefile +205 -0
- data/bin/exerb +185 -0
- data/bin/mkexy +47 -0
- data/doc/LGPL +513 -0
- data/doc/class.ja.html +92 -0
- data/doc/command.ja.html +109 -0
- data/doc/core.ja.html +72 -0
- data/doc/example.ja.html +89 -0
- data/doc/faq.ja.html +59 -0
- data/doc/inside.ja.rd +404 -0
- data/doc/license.ja.html +62 -0
- data/doc/logo.gif +0 -0
- data/doc/misc.ja.html +72 -0
- data/doc/navi.gif +0 -0
- data/doc/recipe.ja.html +317 -0
- data/doc/style.css +187 -0
- data/doc/tutorial.ja.html +182 -0
- data/example/Makefile +54 -0
- data/example/cat_n.rb +14 -0
- data/example/exception.rb +9 -0
- data/example/ext/Win32API.so +0 -0
- data/example/ext/swin.so +0 -0
- data/example/msgbox.rb +14 -0
- data/example/rubytk.rb +22 -0
- data/example/runtime.ico +0 -0
- data/example/runtime.rb +19 -0
- data/example/vr/clipboard.rb +106 -0
- data/example/vr/compat/rubycompat.rb +18 -0
- data/example/vr/compat/vrcomctl.rb +12 -0
- data/example/vr/compat/vrcontrol.rb +50 -0
- data/example/vr/compat/vrmmedia.rb +24 -0
- data/example/vr/contrib/inifile.rb +116 -0
- data/example/vr/contrib/msgboxconst.rb +55 -0
- data/example/vr/contrib/toolbar.rb +371 -0
- data/example/vr/contrib/vrctlcolor.rb +110 -0
- data/example/vr/contrib/vrhotkey.rb +35 -0
- data/example/vr/contrib/vrlistviewex.rb +71 -0
- data/example/vr/contrib/vrstdscrollbar.rb +414 -0
- data/example/vr/contrib/vrwincomponent.rb +54 -0
- data/example/vr/dragdropformat.rb +209 -0
- data/example/vr/rscutil.rb +168 -0
- data/example/vr/sysmod.rb +249 -0
- data/example/vr/vractivex.rb +56 -0
- data/example/vr/vrclipboard.rb +53 -0
- data/example/vr/vrcomctl.rb +1819 -0
- data/example/vr/vrcontrol.rb +1374 -0
- data/example/vr/vrdde.rb +623 -0
- data/example/vr/vrddrop.rb +190 -0
- data/example/vr/vrdialog.rb +406 -0
- data/example/vr/vrhandler.rb +195 -0
- data/example/vr/vrlayout.old.rb +209 -0
- data/example/vr/vrlayout.rb +173 -0
- data/example/vr/vrlayout2.rb +340 -0
- data/example/vr/vrmargin.rb +141 -0
- data/example/vr/vrmgdlayout.rb +381 -0
- data/example/vr/vrmmedia.rb +287 -0
- data/example/vr/vrolednd.rb +192 -0
- data/example/vr/vrowndraw.rb +108 -0
- data/example/vr/vrrichedit.rb +366 -0
- data/example/vr/vrtimer.rb +148 -0
- data/example/vr/vrtooltip.rb +273 -0
- data/example/vr/vrtray.rb +143 -0
- data/example/vr/vrtvitem.rb +118 -0
- data/example/vr/vrtwopane.rb +223 -0
- data/example/vr/vruby.rb +1051 -0
- data/example/vr/winconst.rb +158 -0
- data/example/vruby.rb +38 -0
- data/exerb.gemspec +26 -0
- data/extconf.rb +7 -0
- data/lib/exerb/archive.rb +143 -0
- data/lib/exerb/config.rb +51 -0
- data/lib/exerb/error.rb +15 -0
- data/lib/exerb/executable.rb +68 -0
- data/lib/exerb/file_table.rb +189 -0
- data/lib/exerb/mkexy.rb +81 -0
- data/lib/exerb/name_table.rb +120 -0
- data/lib/exerb/recipe.rb +465 -0
- data/lib/exerb/resource.rb +190 -0
- data/lib/exerb/resource/base.rb +29 -0
- data/lib/exerb/resource/binary.rb +31 -0
- data/lib/exerb/resource/dialog.rb +30 -0
- data/lib/exerb/resource/group_icon.rb +85 -0
- data/lib/exerb/resource/icon.rb +52 -0
- data/lib/exerb/resource/version_info.rb +155 -0
- data/lib/exerb/resource_library.rb +120 -0
- data/lib/exerb/utility.rb +95 -0
- data/lib/exerb/utility2.rb +122 -0
- data/lib/exerb/version.rb +13 -0
- data/lib/exerb/win32/const/resource.rb +51 -0
- data/lib/exerb/win32/icon_file.rb +78 -0
- data/lib/exerb/win32/pe_file.rb +59 -0
- data/lib/exerb/win32/resource_directory.rb +105 -0
- data/lib/exerb/win32/resource_directory_root.rb +67 -0
- data/lib/exerb/win32/resource_entry.rb +98 -0
- data/lib/exerb/win32/struct/base.rb +43 -0
- data/lib/exerb/win32/struct/icon_dir_entry.rb +83 -0
- data/lib/exerb/win32/struct/icon_header.rb +43 -0
- data/lib/exerb/win32/struct/icon_res_entry.rb +48 -0
- data/lib/exerb/win32/struct/image_dos_header.rb +73 -0
- data/lib/exerb/win32/struct/image_file_header.rb +47 -0
- data/lib/exerb/win32/struct/image_nt_headers32.rb +53 -0
- data/lib/exerb/win32/struct/image_optional_header32.rb +107 -0
- data/lib/exerb/win32/struct/image_resource_data_entry.rb +45 -0
- data/lib/exerb/win32/struct/image_resource_directory.rb +47 -0
- data/lib/exerb/win32/struct/image_resource_directory_entry.rb +72 -0
- data/lib/exerb/win32/struct/image_section_header.rb +53 -0
- data/lib/exerb/win32/struct/version_info_block.rb +75 -0
- data/lib/exerb/win32/struct/vs_fixed_file_info.rb +62 -0
- data/src/exerb/cui.c +48 -0
- data/src/exerb/default.rb +1 -0
- data/src/exerb/exerb.c +877 -0
- data/src/exerb/exerb.h +92 -0
- data/src/exerb/gui.c +176 -0
- data/src/exerb/module.c +138 -0
- data/src/exerb/module.h +7 -0
- data/src/exerb/patch.c +27 -0
- data/src/exerb/resource.h +22 -0
- data/src/exerb/resource.rc +121 -0
- data/src/exerb/ruby.ico +0 -0
- data/src/exerb/utility.c +263 -0
- data/src/exerb/utility.h +33 -0
- data/test/alltests.rb +16 -0
- data/test/test-argv.rb +26 -0
- data/test/test-argv/test-argv.rb +9 -0
- data/test/test-argv/test-argv.ret +1 -0
- data/test/test-dollarzero.rb +26 -0
- data/test/test-dollarzero/test-dollarzero.rb +10 -0
- data/test/test-dollarzero/test-dollarzero.ret +2 -0
- data/test/test-dot.rb +26 -0
- data/test/test-dot/dot.dot.dot.rb +9 -0
- data/test/test-dot/dot.dot.rb +9 -0
- data/test/test-dot/test-dot.rb +13 -0
- data/test/test-dot/test-dot.ret +5 -0
- data/test/test-exitcode.rb +28 -0
- data/test/test-exitcode/test-exitcode.rb +9 -0
- data/test/test-kcode.rb +43 -0
- data/test/test-kcode/euc.rb +10 -0
- data/test/test-kcode/euc.ret +2 -0
- data/test/test-kcode/none.rb +10 -0
- data/test/test-kcode/none.ret +2 -0
- data/test/test-kcode/sjis.rb +10 -0
- data/test/test-kcode/sjis.ret +2 -0
- data/test/test-kcode/utf8.rb +10 -0
- data/test/test-kcode/utf8.ret +2 -0
- data/test/test-loadpath.rb +24 -0
- data/test/test-loadpath/test-loadpath.rb +9 -0
- data/test/test-nest.rb +18 -0
- data/test/test-nest/foo.rb +1 -0
- data/test/test-nest/foo/bar.rb +2 -0
- data/test/test-nest/foo/foo.rb +1 -0
- data/test/test-nest/test-nest.rb +1 -0
- data/test/test-nest/test-nest.ret +1 -0
- data/test/test-preload.rb +24 -0
- data/test/test-preload/test-preload.rb +9 -0
- data/test/test-regexp.rb +26 -0
- data/test/test-regexp/test-regexp.rb +23 -0
- data/test/test-regexp/test-regexp.ret +13 -0
- data/test/test-require1.rb +26 -0
- data/test/test-require1/require1.rb +9 -0
- data/test/test-require1/require2.rb +9 -0
- data/test/test-require1/require3.rb +9 -0
- data/test/test-require1/require4.rb +9 -0
- data/test/test-require1/require5.rb +9 -0
- data/test/test-require1/require6.rb +9 -0
- data/test/test-require1/test-require1.rb +41 -0
- data/test/test-require1/test-require1.ret +27 -0
- data/test/test-socket.rb +26 -0
- data/test/test-socket/test-socket.rb +7 -0
- data/test/test-socket/test-socket.ret +1 -0
- data/test/testcase.rb +66 -0
- data/vendor/mkexports.rb +167 -0
- metadata +352 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
#==============================================================================#
|
|
3
|
+
# $Id: image_resource_directory_entry.rb,v 1.5 2005/04/17 15:56:25 yuya Exp $
|
|
4
|
+
#==============================================================================#
|
|
5
|
+
|
|
6
|
+
require 'exerb/win32/struct/base'
|
|
7
|
+
require 'exerb/win32/const/resource'
|
|
8
|
+
|
|
9
|
+
#==============================================================================#
|
|
10
|
+
|
|
11
|
+
module Exerb
|
|
12
|
+
module Win32
|
|
13
|
+
module Struct
|
|
14
|
+
end # Struct
|
|
15
|
+
end # Win32
|
|
16
|
+
end # Exerb
|
|
17
|
+
|
|
18
|
+
#==============================================================================#
|
|
19
|
+
|
|
20
|
+
class Exerb::Win32::Struct::ImageResourceDirectoryEntry < Exerb::Win32::Struct::Base
|
|
21
|
+
|
|
22
|
+
FORMAT = 'LL'
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
super()
|
|
26
|
+
@name = 0
|
|
27
|
+
@offset_to_data = 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_accessor :name, :offset_to_data
|
|
31
|
+
|
|
32
|
+
def pack
|
|
33
|
+
return [@name, @offset_to_data].pack(FORMAT)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def unpack(bin)
|
|
37
|
+
@name, @offset_to_data = bin.unpack(FORMAT)
|
|
38
|
+
return self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def id
|
|
42
|
+
return @name & 0xFFFF
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def name_is_string?
|
|
46
|
+
return (@name & Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING > 0 ? true : false)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def offset_to_string
|
|
50
|
+
return @name & ~Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def offset_to_string=(value)
|
|
54
|
+
@name = value | Exerb::Win32::Const::IMAGE_RESOURCE_NAME_IS_STRING
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def data_is_directory?
|
|
58
|
+
return (@offset_to_data & Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY > 0 ? true : false)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def offset_to_directory
|
|
62
|
+
return @offset_to_data & ~Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def offset_to_directory=(value)
|
|
66
|
+
@offset_to_data = value | Exerb::Win32::Const::IMAGE_RESOURCE_DATA_IS_DIRECTORY
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end # Exerb::Win32::Struct::ImageResourceDirectoryEntry
|
|
70
|
+
|
|
71
|
+
#==============================================================================#
|
|
72
|
+
#==============================================================================#
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
#==============================================================================#
|
|
3
|
+
# $Id: image_section_header.rb,v 1.4 2005/04/17 15:56:25 yuya Exp $
|
|
4
|
+
#==============================================================================#
|
|
5
|
+
|
|
6
|
+
require 'exerb/win32/struct/base'
|
|
7
|
+
|
|
8
|
+
#==============================================================================#
|
|
9
|
+
|
|
10
|
+
module Exerb
|
|
11
|
+
module Win32
|
|
12
|
+
module Struct
|
|
13
|
+
end # Struct
|
|
14
|
+
end # Win32
|
|
15
|
+
end # Exerb
|
|
16
|
+
|
|
17
|
+
#==============================================================================#
|
|
18
|
+
|
|
19
|
+
class Exerb::Win32::Struct::ImageSectionHeader < Exerb::Win32::Struct::Base
|
|
20
|
+
|
|
21
|
+
FORMAT = 'Z8LLLLLLSSL'
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
@name = ""
|
|
25
|
+
@virtual_size = 0
|
|
26
|
+
@virtual_address = 0
|
|
27
|
+
@size_of_raw_data = 0
|
|
28
|
+
@pointer_to_raw_data = 0
|
|
29
|
+
@pointer_to_relocations = 0
|
|
30
|
+
@pointer_to_linenumbers = 0
|
|
31
|
+
@number_of_relocations = 0
|
|
32
|
+
@number_of_linenumbers = 0
|
|
33
|
+
@characteristics = 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
attr_accessor :name, :virtual_size, :virtual_address, :size_of_raw_data, :pointer_to_raw_data, :pointer_to_relocations, :pointer_to_linenumbers, :number_of_relocations, :number_of_linenumbers, :characteristics
|
|
37
|
+
|
|
38
|
+
def pack
|
|
39
|
+
return [@name, @virtual_size, @virtual_address, @size_of_raw_data, @pointer_to_raw_data, @pointer_to_relocations, @pointer_to_linenumbers, @number_of_relocations, @number_of_linenumbers, @characteristics].pack(FORMAT)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def unpack(bin)
|
|
43
|
+
@name, @virtual_size, @virtual_address, @size_of_raw_data, @pointer_to_raw_data, @pointer_to_relocations, @pointer_to_linenumbers, @number_of_relocations, @number_of_linenumbers, @characteristics = bin.unpack(FORMAT)
|
|
44
|
+
return self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias :physical_address :virtual_size
|
|
48
|
+
alias :physical_address= :virtual_size=
|
|
49
|
+
|
|
50
|
+
end # Exerb::Win32::Struct::ImageSectionHeader
|
|
51
|
+
|
|
52
|
+
#==============================================================================#
|
|
53
|
+
#==============================================================================#
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
#==============================================================================#
|
|
3
|
+
# $Id: version_info_block.rb,v 1.5 2005/04/30 15:16:04 yuya Exp $
|
|
4
|
+
#==============================================================================#
|
|
5
|
+
|
|
6
|
+
require 'exerb/utility'
|
|
7
|
+
require 'exerb/win32/struct/base'
|
|
8
|
+
|
|
9
|
+
#==============================================================================#
|
|
10
|
+
|
|
11
|
+
module Exerb
|
|
12
|
+
module Win32
|
|
13
|
+
module Struct
|
|
14
|
+
end # Struct
|
|
15
|
+
end # Win32
|
|
16
|
+
end # Exerb
|
|
17
|
+
|
|
18
|
+
#==============================================================================#
|
|
19
|
+
|
|
20
|
+
class Exerb::Win32::Struct::VersionInfoBlock < Exerb::Win32::Struct::Base
|
|
21
|
+
|
|
22
|
+
def initialize
|
|
23
|
+
@total_length = 0
|
|
24
|
+
@value_length = 0
|
|
25
|
+
@type = 0
|
|
26
|
+
@key = ""
|
|
27
|
+
@data = ""
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_accessor :total_length, :value_length, :type, :key, :data
|
|
31
|
+
|
|
32
|
+
def pack
|
|
33
|
+
return Exerb::Utility.alignment(self.pack_header + self.pack_string, 4) + @data.to_s
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def pack_header
|
|
37
|
+
return [@total_length, @value_length, @type].pack('SSS')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def pack_string
|
|
41
|
+
return @key.to_s + "\0\0"
|
|
42
|
+
end
|
|
43
|
+
protected :pack_string
|
|
44
|
+
|
|
45
|
+
def unpack
|
|
46
|
+
raise NotImplementedError
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def read(io)
|
|
50
|
+
@total_length = io.read(2).unpack('S')[0]
|
|
51
|
+
@value_length = io.read(2).unpack('S')[0]
|
|
52
|
+
@type = io.read(2).unpack('S')[0]
|
|
53
|
+
@key = self.read_string(io)
|
|
54
|
+
@data = io.read(@value_length)
|
|
55
|
+
|
|
56
|
+
return self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def read_string(io)
|
|
60
|
+
str = ''
|
|
61
|
+
|
|
62
|
+
while (ch = io.read(2)) != "\0\0"
|
|
63
|
+
str << ch
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
io.seek((io.pos % 4 == 0 ? 0 : 4 - io.pos % 4), IO::SEEK_CUR)
|
|
67
|
+
|
|
68
|
+
return str
|
|
69
|
+
end
|
|
70
|
+
protected :read_string
|
|
71
|
+
|
|
72
|
+
end # Exerb::Win32::Struct::VersionInfoBlock
|
|
73
|
+
|
|
74
|
+
#==============================================================================#
|
|
75
|
+
#==============================================================================#
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
#==============================================================================#
|
|
3
|
+
# $Id: vs_fixed_file_info.rb,v 1.3 2005/04/17 15:56:25 yuya Exp $
|
|
4
|
+
#==============================================================================#
|
|
5
|
+
|
|
6
|
+
require 'exerb/win32/struct/base'
|
|
7
|
+
|
|
8
|
+
#==============================================================================#
|
|
9
|
+
|
|
10
|
+
module Exerb
|
|
11
|
+
module Win32
|
|
12
|
+
module Struct
|
|
13
|
+
end # Struct
|
|
14
|
+
end # Win32
|
|
15
|
+
end # Exerb
|
|
16
|
+
|
|
17
|
+
#==============================================================================#
|
|
18
|
+
|
|
19
|
+
class Exerb::Win32::Struct::VsFixedFileInfo < Exerb::Win32::Struct::Base
|
|
20
|
+
|
|
21
|
+
FORMAT = 'LLLLLLLLLLLLL'
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
super()
|
|
25
|
+
@signature = 0
|
|
26
|
+
@struct_version = 0
|
|
27
|
+
@file_version_ms = 0
|
|
28
|
+
@file_version_ls = 0
|
|
29
|
+
@product_version_ms = 0
|
|
30
|
+
@product_version_ls = 0
|
|
31
|
+
@file_flags_mask = 0
|
|
32
|
+
@file_flags = 0
|
|
33
|
+
@file_os = 0
|
|
34
|
+
@file_type = 0
|
|
35
|
+
@file_subtype = 0
|
|
36
|
+
@file_date_ms = 0
|
|
37
|
+
@file_date_ls = 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
attr_accessor :signature, :struct_version, :file_version_ms, :file_version_ls, :product_version_ms, :product_version_ls, :file_flags_mask, :file_flags, :file_os, :file_type, :file_subtype, :file_date_ms, :file_date_ls
|
|
41
|
+
|
|
42
|
+
def pack
|
|
43
|
+
return [@signature, @struct_version, @file_version_ms, @file_version_ls, @product_version_ms, @product_version_ls, @file_flags_mask, @file_flags, @file_os, @file_type, @file_subtype, @file_date_ms, @file_date_ls].pack(FORMAT)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def unpack(bin)
|
|
47
|
+
@signature, @struct_version, @file_version_ms, @file_version_ls, @product_version_ms, @product_version_ls, @file_flags_mask, @file_flags, @file_os, @file_type, @file_subtype, @file_date_ms, @file_date_ls = bin.unpack(FORMAT)
|
|
48
|
+
return self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def file_version
|
|
52
|
+
return format('%x.%x.%x.%x', @file_version_ms >> 16, @file_version_ms & 0x0000FFFF, @file_version_ls >> 16, @file_version_ls & 0x0000FFFF)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def product_version
|
|
56
|
+
return format('%x.%x.%x.%x', @product_version_ms >> 16, @product_version_ms & 0x0000FFFF, @product_version_ls >> 16, @product_version_ls & 0x0000FFFF)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end # Exerb::Win32::Struct::VsFixedFileInfo
|
|
60
|
+
|
|
61
|
+
#==============================================================================#
|
|
62
|
+
#==============================================================================#
|
data/src/exerb/cui.c
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// $Id: cui.cpp,v 1.10 2005/04/18 14:40:32 yuya Exp $
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
6
|
+
|
|
7
|
+
int exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE)); // exerb.cpp
|
|
8
|
+
|
|
9
|
+
int main(int argc, char** argv);
|
|
10
|
+
static void on_fail(VALUE errinfo);
|
|
11
|
+
|
|
12
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
13
|
+
|
|
14
|
+
int
|
|
15
|
+
main(int argc, char** argv)
|
|
16
|
+
{
|
|
17
|
+
#ifdef _DEBUG
|
|
18
|
+
__asm { int 3 }
|
|
19
|
+
#endif
|
|
20
|
+
return exerb_main(argc, argv, NULL, on_fail);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static void
|
|
24
|
+
on_fail(VALUE errinfo)
|
|
25
|
+
{
|
|
26
|
+
const VALUE message = rb_funcall(errinfo, rb_intern("message"), 0);
|
|
27
|
+
const VALUE backtrace = rb_funcall(errinfo, rb_intern("backtrace"), 0);
|
|
28
|
+
const VALUE backtrace1 = rb_ary_shift(backtrace);
|
|
29
|
+
const VALUE backtrace2 = rb_str_concat(rb_str_new2("\tfrom "), rb_ary_join(backtrace, rb_str_new2("\n\tfrom ")));
|
|
30
|
+
|
|
31
|
+
#ifdef RUBY19
|
|
32
|
+
fprintf(stderr, "%s: %s (%s)\n",
|
|
33
|
+
rb_string_value_ptr((volatile VALUE*) &backtrace1),
|
|
34
|
+
rb_string_value_ptr((volatile VALUE*) &message),
|
|
35
|
+
rb_obj_classname(errinfo));
|
|
36
|
+
#else
|
|
37
|
+
fprintf(stderr, "%s: %s (%s)\n", STR2CSTR(backtrace1), STR2CSTR(message), rb_obj_classname(errinfo));
|
|
38
|
+
#endif
|
|
39
|
+
if ( FIX2INT(rb_funcall(backtrace, rb_intern("size"), 0)) > 0 ) {
|
|
40
|
+
#ifdef RUBY19
|
|
41
|
+
fprintf(stderr, "%s\n", rb_string_value_ptr((volatile VALUE*) &backtrace2));
|
|
42
|
+
#else
|
|
43
|
+
fprintf(stderr, "%s\n", STR2CSTR(backtrace2));
|
|
44
|
+
#endif
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
raise("please replace an archive.")
|
data/src/exerb/exerb.c
ADDED
|
@@ -0,0 +1,877 @@
|
|
|
1
|
+
// $Id: exerb.cpp,v 1.198 2009/09/08 12:25:47 arton Exp $
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
/* Use crtdbg with Visual Studio or make it no-op */
|
|
6
|
+
#ifdef _MSC_VER
|
|
7
|
+
# include <crtdbg.h>
|
|
8
|
+
#else
|
|
9
|
+
# define _CRT_WARN
|
|
10
|
+
# define _RPT1(...)
|
|
11
|
+
# define _RPT2(...)
|
|
12
|
+
# define _RPT3(...)
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
#include "exerb.h"
|
|
16
|
+
#include "config.h"
|
|
17
|
+
#include "module.h"
|
|
18
|
+
#include "utility.h"
|
|
19
|
+
#include "resource.h"
|
|
20
|
+
|
|
21
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
22
|
+
|
|
23
|
+
typedef struct {
|
|
24
|
+
char *filepath;
|
|
25
|
+
HMODULE handle;
|
|
26
|
+
} LOADED_LIBRARY_ENTRY;
|
|
27
|
+
|
|
28
|
+
typedef struct {
|
|
29
|
+
DWORD base_of_file;
|
|
30
|
+
IMAGE_DOS_HEADER *dos_header;
|
|
31
|
+
IMAGE_NT_HEADERS *nt_headers;
|
|
32
|
+
IMAGE_SECTION_HEADER *section;
|
|
33
|
+
DWORD base_of_import_table;
|
|
34
|
+
DWORD delta_of_import_table;
|
|
35
|
+
DWORD base_of_name_pool;
|
|
36
|
+
DWORD size_of_name_pool;
|
|
37
|
+
} IMPORT_TABLE_INFO;
|
|
38
|
+
|
|
39
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
40
|
+
|
|
41
|
+
VALUE rb_mExerbRuntime = 0;
|
|
42
|
+
VALUE rb_eExerbRuntimeError = 0;
|
|
43
|
+
|
|
44
|
+
ARCHIVE_HEADER *g_archive_header = NULL;
|
|
45
|
+
NAME_TABLE_HEADER *g_name_table_header = NULL;
|
|
46
|
+
FILE_TABLE_HEADER *g_file_table_header = NULL;
|
|
47
|
+
|
|
48
|
+
int g_loaded_library_count = 0;
|
|
49
|
+
LOADED_LIBRARY_ENTRY g_loaded_library_table[32] = {0};
|
|
50
|
+
LOADED_LIBRARY_ENTRY g_pre_loaded_library_table[8] = {0};
|
|
51
|
+
|
|
52
|
+
int g_loaded_resource_count = 0;
|
|
53
|
+
HMODULE g_loaded_resource_table[4] = {0};
|
|
54
|
+
|
|
55
|
+
VALUE rb_load_path;
|
|
56
|
+
VALUE rb_argv0;
|
|
57
|
+
#ifndef RUBY19
|
|
58
|
+
VALUE rb_progname;
|
|
59
|
+
#endif
|
|
60
|
+
|
|
61
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
62
|
+
|
|
63
|
+
#ifdef RUBY19
|
|
64
|
+
/* miniprelude.c, prelude.c */
|
|
65
|
+
void Init_prelude(void);
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
#ifdef RUBY19_COMPILED_CODE
|
|
69
|
+
/* not exposed by Ruby headers (only in iseq.h), so we define it here */
|
|
70
|
+
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
|
|
71
|
+
#endif
|
|
72
|
+
|
|
73
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
74
|
+
|
|
75
|
+
int exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE));
|
|
76
|
+
static VALUE exerb_main_in_protect(VALUE replace_io);
|
|
77
|
+
static void exerb_mapping();
|
|
78
|
+
static void exerb_set_script_name(char* name);
|
|
79
|
+
static void exerb_setup_kcode();
|
|
80
|
+
static void exerb_setup_resource_library();
|
|
81
|
+
static void exerb_execute();
|
|
82
|
+
static void exerb_cleanup();
|
|
83
|
+
static int exerb_find_ruby_pre_loaded(const VALUE filename);
|
|
84
|
+
static int exerb_find_file_pre_loaded(const VALUE filename, VALUE *feature, LOADED_LIBRARY_ENTRY **loaded_library_entry);
|
|
85
|
+
static int exerb_find_file_inside(const VALUE filename, WORD *id, VALUE *feature, VALUE *realname);
|
|
86
|
+
static int exerb_find_file_outside(const VALUE filename, VALUE *feature, VALUE *realname);
|
|
87
|
+
static VALUE exerb_load_ruby_script(const FILE_ENTRY_HEADER *file_entry);
|
|
88
|
+
static VALUE exerb_load_ruby_script_from_file(const char *filepath);
|
|
89
|
+
#ifdef RUBY19_COMPILED_CODE
|
|
90
|
+
static VALUE exerb_load_compiled_script(const FILE_ENTRY_HEADER *file_entry);
|
|
91
|
+
#endif
|
|
92
|
+
static void exerb_load_extension_library(const FILE_ENTRY_HEADER *file_entry);
|
|
93
|
+
static void exerb_load_extension_library_from_file(const char *filepath);
|
|
94
|
+
static HMODULE exerb_load_library(const FILE_ENTRY_HEADER *file_entry);
|
|
95
|
+
static HMODULE exerb_load_library_ex(const char *base_of_file, const int size_of_file, const char* filepath, int no_replace_function);
|
|
96
|
+
static HMODULE exerb_preload_library(const FILE_ENTRY_HEADER *file_entry);
|
|
97
|
+
static int exerb_replace_import_dll(const char *base_of_file);
|
|
98
|
+
static void exerb_replace_import_dll_name(IMPORT_TABLE_INFO *info, const char *src_name, const char* new_name);
|
|
99
|
+
static int exerb_get_import_table_info(const char *base_of_file, IMPORT_TABLE_INFO *info);
|
|
100
|
+
static IMAGE_SECTION_HEADER* exerb_get_enclosing_section_header(const IMAGE_NT_HEADERS *nt_headers, const DWORD rva);
|
|
101
|
+
static void exerb_call_initialize_function(const HMODULE handle, const char *filepath);
|
|
102
|
+
static int exerb_find_resource(const DWORD base_of_image, const int type, const int id, DWORD *base_of_item, DWORD *size_of_item);
|
|
103
|
+
|
|
104
|
+
static void exerb_replace_import_function(const HMODULE module);
|
|
105
|
+
static int exerb_replace_import_function_thunk(const HMODULE module, const FARPROC src_proc, const FARPROC new_proc);
|
|
106
|
+
static HMODULE WINAPI exerb_hook_load_library(LPCTSTR filename);
|
|
107
|
+
static HMODULE WINAPI exerb_hook_load_library_ex(LPCTSTR filename, HANDLE file, DWORD flags);
|
|
108
|
+
static HMODULE WINAPI exerb_hook_get_module_handle(LPCTSTR filename);
|
|
109
|
+
static FARPROC WINAPI exerb_hook_get_proc_address(HMODULE module, LPCTSTR procname);
|
|
110
|
+
|
|
111
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
112
|
+
|
|
113
|
+
int
|
|
114
|
+
exerb_main(int argc, char** argv, void (*on_init)(VALUE, VALUE, VALUE), void (*on_fail)(VALUE))
|
|
115
|
+
{
|
|
116
|
+
#ifdef RUBY19
|
|
117
|
+
ruby_sysinit(&argc, &argv);
|
|
118
|
+
RUBY_INIT_STACK;
|
|
119
|
+
ruby_init();
|
|
120
|
+
#else
|
|
121
|
+
NtInitialize(&argc, &argv);
|
|
122
|
+
ruby_init();
|
|
123
|
+
rb_ary_push(rb_load_path, rb_str_new2("."));
|
|
124
|
+
#endif
|
|
125
|
+
// argc = rb_w32_cmdvector(GetCommandLine(), &argv);
|
|
126
|
+
ruby_set_argv(argc - 1, argv + 1);
|
|
127
|
+
exerb_set_script_name((char *)"exerb");
|
|
128
|
+
|
|
129
|
+
int state = 0, result_code = 0;
|
|
130
|
+
rb_protect(exerb_main_in_protect, UINT2NUM((DWORD)on_init), &state);
|
|
131
|
+
|
|
132
|
+
if ( state ) {
|
|
133
|
+
#ifdef RUBY19
|
|
134
|
+
VALUE errinfo = rb_errinfo();
|
|
135
|
+
#else
|
|
136
|
+
VALUE errinfo = ruby_errinfo;
|
|
137
|
+
#endif
|
|
138
|
+
if ( rb_obj_is_kind_of(errinfo, rb_eSystemExit) ) {
|
|
139
|
+
result_code = FIX2INT(rb_iv_get(errinfo, "status"));
|
|
140
|
+
} else {
|
|
141
|
+
on_fail(errinfo);
|
|
142
|
+
result_code = 1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
ruby_finalize();
|
|
147
|
+
exerb_cleanup();
|
|
148
|
+
|
|
149
|
+
return result_code;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static VALUE
|
|
153
|
+
exerb_main_in_protect(VALUE on_init_proc)
|
|
154
|
+
{
|
|
155
|
+
Init_ExerbRuntime();
|
|
156
|
+
|
|
157
|
+
void (*on_init)(VALUE, VALUE, VALUE) = (void(*)(VALUE, VALUE, VALUE))NUM2UINT(on_init_proc);
|
|
158
|
+
if ( on_init ) on_init(rb_stdin, rb_stdout, rb_stderr);
|
|
159
|
+
|
|
160
|
+
/* Hack require */
|
|
161
|
+
rb_define_global_function("require", exerb_rb_f_require, 1);
|
|
162
|
+
|
|
163
|
+
exerb_mapping();
|
|
164
|
+
exerb_setup_kcode();
|
|
165
|
+
exerb_setup_resource_library();
|
|
166
|
+
exerb_execute();
|
|
167
|
+
|
|
168
|
+
return Qnil;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static void
|
|
172
|
+
exerb_mapping()
|
|
173
|
+
{
|
|
174
|
+
const DWORD base_of_image = (DWORD)GetModuleHandle(NULL);
|
|
175
|
+
DWORD base_of_archive = 0, size_of_archive = 0;
|
|
176
|
+
if ( !exerb_find_resource(base_of_image, RT_EXERB, ID_EXERB, &base_of_archive, &size_of_archive) ) {
|
|
177
|
+
rb_raise(rb_eExerbRuntimeError, "The executable hasn't an archive.");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
g_archive_header = (ARCHIVE_HEADER*)base_of_archive;
|
|
181
|
+
if ( g_archive_header->signature1 != ARCHIVE_HEADER_SIGNATURE1 ||
|
|
182
|
+
g_archive_header->signature2 != ARCHIVE_HEADER_SIGNATURE2 ) {
|
|
183
|
+
rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of archive header.");
|
|
184
|
+
}
|
|
185
|
+
if ( g_archive_header->offset_of_name_table == 0 ||
|
|
186
|
+
g_archive_header->offset_of_file_table == 0 ) {
|
|
187
|
+
rb_raise(rb_eExerbRuntimeError, "The executable has invalid archive header.");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
g_name_table_header = (NAME_TABLE_HEADER*)(base_of_archive + g_archive_header->offset_of_name_table);
|
|
191
|
+
g_file_table_header = (FILE_TABLE_HEADER*)(base_of_archive + g_archive_header->offset_of_file_table);
|
|
192
|
+
|
|
193
|
+
if ( g_name_table_header->signature != NAME_TABLE_HEADER_SIGNATURE ) {
|
|
194
|
+
rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of the name table header.");
|
|
195
|
+
}
|
|
196
|
+
if ( g_file_table_header->signature != FILE_TABLE_HEADER_SIGNATURE ) {
|
|
197
|
+
rb_raise(rb_eExerbRuntimeError, "The executable has invalid signature of the file table header.");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
static void
|
|
202
|
+
exerb_set_script_name(char* name)
|
|
203
|
+
{
|
|
204
|
+
ruby_script(name);
|
|
205
|
+
#ifdef RUBY19
|
|
206
|
+
rb_argv0 = rb_str_new2(name);
|
|
207
|
+
#else
|
|
208
|
+
rb_argv0 = rb_progname;
|
|
209
|
+
#endif
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static void
|
|
213
|
+
exerb_setup_kcode()
|
|
214
|
+
{
|
|
215
|
+
#ifndef RUBY19
|
|
216
|
+
switch ( g_archive_header->kcode ) {
|
|
217
|
+
case ARCHIVE_HEADER_OPTIONS_KCODE_NONE: rb_set_kcode("n"); break;
|
|
218
|
+
case ARCHIVE_HEADER_OPTIONS_KCODE_EUC: rb_set_kcode("e"); break;
|
|
219
|
+
case ARCHIVE_HEADER_OPTIONS_KCODE_SJIS: rb_set_kcode("s"); break;
|
|
220
|
+
case ARCHIVE_HEADER_OPTIONS_KCODE_UTF8: _from_filerb_set_kcode("u"); break;
|
|
221
|
+
}
|
|
222
|
+
#else
|
|
223
|
+
exerb_require(rb_str_new2("enc/encdb"));
|
|
224
|
+
exerb_require(rb_str_new2("enc/utf_16le"));
|
|
225
|
+
exerb_require(rb_str_new2("enc/trans/transdb"));
|
|
226
|
+
exerb_require(rb_str_new2("enc/trans/utf_16_32"));
|
|
227
|
+
exerb_require(rb_str_new2("enc/trans/single_byte"));
|
|
228
|
+
Init_prelude();
|
|
229
|
+
#endif
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static void
|
|
233
|
+
exerb_setup_resource_library()
|
|
234
|
+
{
|
|
235
|
+
FILE_ENTRY_HEADER *file_entry = exerb_get_first_file_entry();
|
|
236
|
+
|
|
237
|
+
for ( int i = 0; i < g_file_table_header->number_of_headers; i++, file_entry++ ) {
|
|
238
|
+
if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_RESOURCE_LIBRARY ) {
|
|
239
|
+
if ( (unsigned int)g_loaded_resource_count > sizeof(g_loaded_resource_table) / sizeof(HMODULE) ) {
|
|
240
|
+
rb_raise(rb_eExerbRuntimeError, "the loaded recourse table is too big.");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
g_loaded_resource_table[g_loaded_resource_count] = exerb_load_library(file_entry);
|
|
244
|
+
g_loaded_resource_count++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static void
|
|
250
|
+
exerb_execute()
|
|
251
|
+
{
|
|
252
|
+
FILE_ENTRY_HEADER *file_entry = exerb_get_first_file_entry();
|
|
253
|
+
|
|
254
|
+
for ( int i = 0; i < g_file_table_header->number_of_headers; i++, file_entry++ ) {
|
|
255
|
+
if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_RUBY_SCRIPT ) {
|
|
256
|
+
exerb_set_script_name(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
|
|
257
|
+
exerb_load_ruby_script(file_entry);
|
|
258
|
+
return;
|
|
259
|
+
#ifdef RUBY19_COMPILED_CODE
|
|
260
|
+
} else if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_COMPILED_SCRIPT ) {
|
|
261
|
+
exerb_set_script_name(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
|
|
262
|
+
exerb_load_compiled_script(file_entry);
|
|
263
|
+
return;
|
|
264
|
+
#endif
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
rb_raise(rb_eExerbRuntimeError, "The startup script was not found.");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static void
|
|
272
|
+
exerb_cleanup()
|
|
273
|
+
{
|
|
274
|
+
for ( int i = g_loaded_library_count; i > 0; i-- ) {
|
|
275
|
+
const LOADED_LIBRARY_ENTRY *entry = &g_loaded_library_table[i - 1];
|
|
276
|
+
char filepath[MAX_PATH] = "";
|
|
277
|
+
GetModuleFileName(entry->handle, filepath, sizeof(filepath));
|
|
278
|
+
FreeLibrary(entry->handle);
|
|
279
|
+
DeleteFile(filepath);
|
|
280
|
+
free(entry->filepath);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
VALUE
|
|
285
|
+
exerb_rb_f_require(VALUE obj, VALUE fname)
|
|
286
|
+
{
|
|
287
|
+
return exerb_require(fname);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
VALUE
|
|
291
|
+
exerb_require(VALUE fname)
|
|
292
|
+
{
|
|
293
|
+
#ifdef RUBY19
|
|
294
|
+
SafeStringValue(fname);
|
|
295
|
+
#else
|
|
296
|
+
Check_SafeStr(fname);
|
|
297
|
+
#endif
|
|
298
|
+
LOADED_LIBRARY_ENTRY *loaded_library_entry = NULL;
|
|
299
|
+
WORD id = 0;
|
|
300
|
+
VALUE feature = Qnil, realname = Qnil;
|
|
301
|
+
|
|
302
|
+
if ( exerb_find_ruby_pre_loaded(fname) ) {
|
|
303
|
+
return Qfalse;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if ( exerb_find_file_pre_loaded(fname, &feature, &loaded_library_entry) ) {
|
|
307
|
+
rb_provide(RSTRING_PTR(feature));
|
|
308
|
+
exerb_call_initialize_function(loaded_library_entry->handle, loaded_library_entry->filepath);
|
|
309
|
+
free(loaded_library_entry->filepath);
|
|
310
|
+
loaded_library_entry->filepath = NULL;
|
|
311
|
+
loaded_library_entry->handle = NULL;
|
|
312
|
+
return Qtrue;
|
|
313
|
+
} else if ( exerb_find_file_inside(fname, &id, &feature, &realname) ) {
|
|
314
|
+
if ( rb_provided(RSTRING_PTR(feature)) ) return Qfalse;
|
|
315
|
+
|
|
316
|
+
FILE_ENTRY_HEADER *file_entry = exerb_find_file_entry(id);
|
|
317
|
+
|
|
318
|
+
switch ( file_entry->type_of_file ) {
|
|
319
|
+
case FILE_ENTRY_HEADER_TYPE_RUBY_SCRIPT:
|
|
320
|
+
rb_provide(RSTRING_PTR(feature));
|
|
321
|
+
exerb_load_ruby_script(file_entry);
|
|
322
|
+
return Qtrue;
|
|
323
|
+
#ifdef RUBY19_COMPILED_CODE
|
|
324
|
+
case FILE_ENTRY_HEADER_TYPE_COMPILED_SCRIPT:
|
|
325
|
+
rb_provide(RSTRING_PTR(feature));
|
|
326
|
+
exerb_load_compiled_script(file_entry);
|
|
327
|
+
return Qtrue;
|
|
328
|
+
#endif
|
|
329
|
+
case FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY:
|
|
330
|
+
rb_provide(RSTRING_PTR(feature));
|
|
331
|
+
exerb_load_extension_library(file_entry);
|
|
332
|
+
return Qtrue;
|
|
333
|
+
}
|
|
334
|
+
} else if ( exerb_find_file_outside(fname, &feature, &realname) ) {
|
|
335
|
+
if ( rb_provided(RSTRING_PTR(feature)) ) return Qfalse;
|
|
336
|
+
|
|
337
|
+
const char *ext = strrchr(RSTRING_PTR(feature), '.');
|
|
338
|
+
|
|
339
|
+
if ( stricmp(ext, ".rb") == 0 ) {
|
|
340
|
+
rb_provide(RSTRING_PTR(feature));
|
|
341
|
+
exerb_load_ruby_script_from_file(RSTRING_PTR(realname));
|
|
342
|
+
return Qtrue;
|
|
343
|
+
} else if ( stricmp(ext, ".so") == 0 ) {
|
|
344
|
+
rb_provide(RSTRING_PTR(feature));
|
|
345
|
+
exerb_load_extension_library_from_file(RSTRING_PTR(realname));
|
|
346
|
+
return Qtrue;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING_PTR(fname));
|
|
351
|
+
|
|
352
|
+
return Qfalse;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
static char* EXTTBL[] = {(char *)"rb", (char *)"so", (char *)"dll" };
|
|
356
|
+
|
|
357
|
+
static int
|
|
358
|
+
exerb_find_ruby_pre_loaded(const VALUE filename)
|
|
359
|
+
{
|
|
360
|
+
const char* fname = RSTRING_PTR(filename);
|
|
361
|
+
if (strchr(fname, '.')) {
|
|
362
|
+
return rb_provided(fname) != Qfalse ? 1 : 0;
|
|
363
|
+
} else {
|
|
364
|
+
char* p = (char*)_alloca(strlen(fname) + 8);
|
|
365
|
+
for (int i = 0; (unsigned int)i < sizeof(EXTTBL)/sizeof(EXTTBL[0]); i++) {
|
|
366
|
+
sprintf(p, "%s.%s", fname, EXTTBL[i]);
|
|
367
|
+
if (rb_provided(p)) {
|
|
368
|
+
return 1;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static int
|
|
376
|
+
exerb_find_file_pre_loaded(const VALUE filename, VALUE *feature, LOADED_LIBRARY_ENTRY **loaded_library_entry)
|
|
377
|
+
{
|
|
378
|
+
const char *fname = RSTRING_PTR(filename);
|
|
379
|
+
|
|
380
|
+
for ( int i = 0; (unsigned int)i < sizeof(g_pre_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY); i++ ) {
|
|
381
|
+
const char *name = g_pre_loaded_library_table[i].filepath;
|
|
382
|
+
if ( !name ) continue;
|
|
383
|
+
|
|
384
|
+
if ( stricmp(name, fname) == 0 ) {
|
|
385
|
+
*feature = rb_str_new2(name);
|
|
386
|
+
*loaded_library_entry = &g_pre_loaded_library_table[i];
|
|
387
|
+
return 1;
|
|
388
|
+
} else if ( exerb_cmp_filename_with_ext(name, fname, "so") ) {
|
|
389
|
+
*feature = rb_str_new2(name);
|
|
390
|
+
*loaded_library_entry = &g_pre_loaded_library_table[i];
|
|
391
|
+
return 1;
|
|
392
|
+
} else if ( exerb_cmp_filename_with_ext(name, fname, "dll") ) {
|
|
393
|
+
*feature = rb_str_concat(rb_str_new2(fname), rb_str_new2(".so"));
|
|
394
|
+
*loaded_library_entry = &g_pre_loaded_library_table[i];
|
|
395
|
+
return 1;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
static int
|
|
403
|
+
exerb_find_file_inside(const VALUE filename, WORD *id, VALUE *feature, VALUE *realname)
|
|
404
|
+
{
|
|
405
|
+
#ifdef RUBY19
|
|
406
|
+
const char *fname = rb_string_value_ptr((volatile VALUE*) &filename);
|
|
407
|
+
#else
|
|
408
|
+
const char *fname = STR2CSTR(filename);
|
|
409
|
+
#endif
|
|
410
|
+
|
|
411
|
+
NAME_ENTRY_HEADER *name_entry = exerb_get_first_name_entry();
|
|
412
|
+
|
|
413
|
+
for ( int i = 0; i < g_name_table_header->number_of_headers; i++, name_entry++ ) {
|
|
414
|
+
const char *name = exerb_get_name_from_entry(name_entry);
|
|
415
|
+
|
|
416
|
+
if ( strcmp(name, fname) == 0 ) {
|
|
417
|
+
*id = name_entry->id;
|
|
418
|
+
*feature = rb_str_new2(name);
|
|
419
|
+
*realname = rb_str_new2(name);
|
|
420
|
+
return 1;
|
|
421
|
+
} else if ( exerb_cmp_filename_with_ext(name, fname, "rb") ) {
|
|
422
|
+
*id = name_entry->id;
|
|
423
|
+
*feature = rb_str_new2(name);
|
|
424
|
+
*realname = rb_str_new2(name);
|
|
425
|
+
return 1;
|
|
426
|
+
} else if ( exerb_cmp_filename_with_ext(name, fname, "so") ) {
|
|
427
|
+
*id = name_entry->id;
|
|
428
|
+
*feature = rb_str_new2(name);
|
|
429
|
+
*realname = rb_str_new2(name);
|
|
430
|
+
return 1;
|
|
431
|
+
} else if ( exerb_cmp_filename_with_ext(name, fname, "dll") ) {
|
|
432
|
+
FILE_ENTRY_HEADER* file_entry = exerb_find_file_entry(name_entry->id);
|
|
433
|
+
if (file_entry->type_of_file != FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY) continue;
|
|
434
|
+
|
|
435
|
+
*id = name_entry->id;
|
|
436
|
+
*feature = rb_str_concat(rb_str_new2(fname), rb_str_new2(".so"));
|
|
437
|
+
*realname = rb_str_new2(name);
|
|
438
|
+
return 1;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
*id = 0;
|
|
443
|
+
*feature = Qnil;
|
|
444
|
+
*realname = Qnil;
|
|
445
|
+
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
static int
|
|
450
|
+
exerb_find_file_outside(const VALUE filename, VALUE *feature, VALUE *realname)
|
|
451
|
+
{
|
|
452
|
+
const VALUE filename_rb = rb_str_concat(rb_str_dup(filename), rb_str_new2(".rb"));
|
|
453
|
+
const VALUE filename_so = rb_str_concat(rb_str_dup(filename), rb_str_new2(".so"));
|
|
454
|
+
const VALUE filename_dll = rb_str_concat(rb_str_dup(filename), rb_str_new2(".dll"));
|
|
455
|
+
|
|
456
|
+
if ( *realname = rb_find_file(*feature = filename) ) return 1;
|
|
457
|
+
if ( *realname = rb_find_file(*feature = filename_rb) ) return 1;
|
|
458
|
+
if ( *realname = rb_find_file(*feature = filename_so) ) return 1;
|
|
459
|
+
if ( *realname = rb_find_file(filename_dll) ) { *feature = filename_so; return 1; }
|
|
460
|
+
|
|
461
|
+
*feature = Qnil;
|
|
462
|
+
*realname = Qnil;
|
|
463
|
+
|
|
464
|
+
return 0;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
static VALUE
|
|
468
|
+
exerb_load_ruby_script(const FILE_ENTRY_HEADER *file_entry)
|
|
469
|
+
{
|
|
470
|
+
ID id_eval = rb_intern("eval");
|
|
471
|
+
VALUE binding = rb_const_get(rb_mKernel, rb_intern("TOPLEVEL_BINDING"));
|
|
472
|
+
VALUE lineno = INT2FIX(1);
|
|
473
|
+
|
|
474
|
+
const VALUE code = exerb_get_file_from_entry2(file_entry);
|
|
475
|
+
const VALUE name = rb_str_new2(exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id)));
|
|
476
|
+
|
|
477
|
+
return rb_funcall(rb_mKernel, id_eval, 4, code, binding, name, lineno);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
static VALUE
|
|
481
|
+
exerb_load_ruby_script_from_file(const char *filepath)
|
|
482
|
+
{
|
|
483
|
+
rb_load(rb_str_new2(filepath), 0);
|
|
484
|
+
return Qnil;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
#ifdef RUBY19_COMPILED_CODE
|
|
488
|
+
static VALUE
|
|
489
|
+
exerb_load_compiled_script(const FILE_ENTRY_HEADER *file_entry)
|
|
490
|
+
{
|
|
491
|
+
ID id_eval = rb_intern("eval");
|
|
492
|
+
const VALUE code = exerb_get_file_from_entry2(file_entry);
|
|
493
|
+
const VALUE iseq_ary = rb_marshal_load(code);
|
|
494
|
+
const VALUE iseq = rb_iseq_load(iseq_ary, Qnil, Qnil);
|
|
495
|
+
|
|
496
|
+
return rb_funcall(iseq, id_eval, 0);
|
|
497
|
+
}
|
|
498
|
+
#endif
|
|
499
|
+
|
|
500
|
+
static void
|
|
501
|
+
exerb_load_extension_library(const FILE_ENTRY_HEADER *file_entry)
|
|
502
|
+
{
|
|
503
|
+
const HMODULE handle = exerb_load_library(file_entry);
|
|
504
|
+
const char *filepath = exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id));
|
|
505
|
+
exerb_call_initialize_function(handle, filepath);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
static void
|
|
509
|
+
exerb_load_extension_library_from_file(const char *filepath)
|
|
510
|
+
{
|
|
511
|
+
const HANDLE file = exerb_fopen_for_read(filepath);
|
|
512
|
+
const DWORD size = exerb_fsize(file);
|
|
513
|
+
char *buffer = malloc(size);
|
|
514
|
+
exerb_fread(file, buffer, size);
|
|
515
|
+
exerb_fclose(file);
|
|
516
|
+
|
|
517
|
+
const HMODULE handle = exerb_load_library_ex(buffer, size, filepath, 0);
|
|
518
|
+
exerb_call_initialize_function(handle, filepath);
|
|
519
|
+
|
|
520
|
+
free(buffer);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
static HMODULE
|
|
524
|
+
exerb_load_library(const FILE_ENTRY_HEADER *file_entry)
|
|
525
|
+
{
|
|
526
|
+
const char *base_of_file = exerb_get_file_from_entry1(file_entry);
|
|
527
|
+
const char *filepath = exerb_get_name_from_entry(exerb_find_name_entry(file_entry->id));
|
|
528
|
+
return exerb_load_library_ex(base_of_file, file_entry->size_of_file, filepath, (int)file_entry->flag_no_replace_function);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
static HMODULE
|
|
532
|
+
exerb_load_library_ex(const char *base_of_file, const int size_of_file, const char* filepath, int no_replace_function)
|
|
533
|
+
{
|
|
534
|
+
if ((unsigned int)g_loaded_library_count > sizeof(g_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY) ) {
|
|
535
|
+
rb_raise(rb_eExerbRuntimeError, "the loaded library table is too big.");
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
DWORD protect = 0, dummy = 0;
|
|
539
|
+
VirtualProtect((void*)base_of_file, size_of_file, PAGE_READWRITE, &protect);
|
|
540
|
+
exerb_replace_import_dll(base_of_file);
|
|
541
|
+
VirtualProtect((void*)base_of_file, size_of_file, protect, &dummy);
|
|
542
|
+
|
|
543
|
+
char tmp_filepath[MAX_PATH] = "";
|
|
544
|
+
exerb_create_tmpfile("exerb", tmp_filepath, base_of_file, size_of_file);
|
|
545
|
+
|
|
546
|
+
const HMODULE handle = LoadLibraryEx(tmp_filepath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
547
|
+
if ( !handle ) {
|
|
548
|
+
DWORD error = GetLastError();
|
|
549
|
+
DeleteFile(tmp_filepath);
|
|
550
|
+
exerb_raise_runtime_error(error);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
g_loaded_library_table[g_loaded_library_count].filepath = exerb_strdup(filepath);
|
|
554
|
+
g_loaded_library_table[g_loaded_library_count].handle = handle;
|
|
555
|
+
g_loaded_library_count++;
|
|
556
|
+
|
|
557
|
+
if ( !no_replace_function ) exerb_replace_import_function(handle);
|
|
558
|
+
|
|
559
|
+
return handle;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
static HMODULE
|
|
563
|
+
exerb_preload_library(const FILE_ENTRY_HEADER *file_entry)
|
|
564
|
+
{
|
|
565
|
+
NAME_ENTRY_HEADER *name_entry = exerb_find_name_entry(file_entry->id);
|
|
566
|
+
const char *name = exerb_get_name_from_entry(name_entry);
|
|
567
|
+
|
|
568
|
+
for ( int i = 0; i < g_loaded_library_count; i++ ) {
|
|
569
|
+
if ( g_loaded_library_table[i].filepath && stricmp(g_loaded_library_table[i].filepath, name) == 0 ) {
|
|
570
|
+
return g_loaded_library_table[i].handle;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
HMODULE module = exerb_load_library(file_entry);
|
|
575
|
+
|
|
576
|
+
if (file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ) {
|
|
577
|
+
for ( int i = 0; (unsigned int)i < sizeof(g_pre_loaded_library_table) / sizeof(LOADED_LIBRARY_ENTRY); i++ ) {
|
|
578
|
+
if ( !g_pre_loaded_library_table[i].handle ) {
|
|
579
|
+
g_pre_loaded_library_table[i].filepath = exerb_strdup(name);
|
|
580
|
+
g_pre_loaded_library_table[i].handle = module;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return module;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
static int
|
|
590
|
+
exerb_replace_import_dll(const char *base_of_file)
|
|
591
|
+
{
|
|
592
|
+
IMPORT_TABLE_INFO info = {0};
|
|
593
|
+
if ( !exerb_get_import_table_info(base_of_file, &info) ) return 0;
|
|
594
|
+
|
|
595
|
+
char self_filepath[MAX_PATH] = "";
|
|
596
|
+
const char *self_filename = exerb_get_self_filepath(self_filepath, sizeof(self_filepath));
|
|
597
|
+
|
|
598
|
+
exerb_replace_import_dll_name(&info, EXERB_LIBRUBY_SO, self_filename);
|
|
599
|
+
|
|
600
|
+
return 1;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
static void
|
|
604
|
+
exerb_replace_import_dll_name(IMPORT_TABLE_INFO *info, const char *src_name, const char* new_name)
|
|
605
|
+
{
|
|
606
|
+
const DWORD base_of_name = info->base_of_file - info->delta_of_import_table;
|
|
607
|
+
const DWORD size_of_new_name = strlen(new_name);
|
|
608
|
+
FILE_ENTRY_HEADER *file_entry;
|
|
609
|
+
|
|
610
|
+
IMAGE_IMPORT_DESCRIPTOR *first_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)(info->base_of_file + info->base_of_import_table);
|
|
611
|
+
|
|
612
|
+
for ( IMAGE_IMPORT_DESCRIPTOR *descriptor = first_descriptor; descriptor->Name; descriptor++ ) {
|
|
613
|
+
char *name = (char*)(base_of_name + descriptor->Name);
|
|
614
|
+
|
|
615
|
+
if ( stricmp(name, src_name) == 0 ) {
|
|
616
|
+
int found = 0;
|
|
617
|
+
for ( IMAGE_IMPORT_DESCRIPTOR *desc = first_descriptor; desc->Name; desc++ ) {
|
|
618
|
+
if ( strcmp((char*)(base_of_name + desc->Name), new_name) == 0 ) {
|
|
619
|
+
descriptor->Name = desc->Name;
|
|
620
|
+
found = 1;
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if ( found ) continue;
|
|
625
|
+
|
|
626
|
+
if ( strlen(name) >= size_of_new_name ) {
|
|
627
|
+
strcpy(name, new_name);
|
|
628
|
+
} else if ( size_of_new_name + 1 <= info->size_of_name_pool ) {
|
|
629
|
+
DWORD address_of_new_name = info->base_of_name_pool - (size_of_new_name + 1);
|
|
630
|
+
|
|
631
|
+
strcpy((char*)(info->base_of_file + address_of_new_name), new_name);
|
|
632
|
+
descriptor->Name = address_of_new_name + info->delta_of_import_table;
|
|
633
|
+
|
|
634
|
+
info->base_of_name_pool -= size_of_new_name + 1;
|
|
635
|
+
info->size_of_name_pool -= size_of_new_name + 1;
|
|
636
|
+
} else {
|
|
637
|
+
rb_raise(rb_eLoadError, "Couldn't modify DLL's name in the import table. The name of the executable file is too long.");
|
|
638
|
+
}
|
|
639
|
+
} else if ( file_entry = exerb_find_file_entry_by_filename(name, NULL) ) {
|
|
640
|
+
if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
|
|
641
|
+
file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
|
|
642
|
+
HMODULE module = exerb_preload_library(file_entry);
|
|
643
|
+
char filepath[MAX_PATH] = "";
|
|
644
|
+
const char *filename = exerb_get_module_filepath(module, filepath, sizeof(filepath));
|
|
645
|
+
exerb_replace_import_dll_name(info, name, filename);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
static int
|
|
652
|
+
exerb_get_import_table_info(const char *base_of_file, IMPORT_TABLE_INFO *info)
|
|
653
|
+
{
|
|
654
|
+
info->base_of_file = (DWORD)base_of_file;
|
|
655
|
+
info->dos_header = (IMAGE_DOS_HEADER*)info->base_of_file;
|
|
656
|
+
info->nt_headers = (IMAGE_NT_HEADERS*)(info->base_of_file + info->dos_header->e_lfanew);
|
|
657
|
+
|
|
658
|
+
const DWORD rva_of_import_table = info->nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
659
|
+
|
|
660
|
+
info->section = exerb_get_enclosing_section_header(info->nt_headers, rva_of_import_table);
|
|
661
|
+
if ( !info->section ) return 0;
|
|
662
|
+
|
|
663
|
+
info->delta_of_import_table = info->section->VirtualAddress - info->section->PointerToRawData;
|
|
664
|
+
info->base_of_import_table = rva_of_import_table - info->delta_of_import_table;
|
|
665
|
+
|
|
666
|
+
if ( strnicmp((char*)info->section->Name, ".idata", 8) == 0 || // for Boland's Compiler
|
|
667
|
+
strnicmp((char*)info->section->Name, ".rdata", 8) == 0 ) { // for Microsoft's Compiler
|
|
668
|
+
info->base_of_name_pool = info->section->PointerToRawData + info->section->SizeOfRawData;
|
|
669
|
+
info->size_of_name_pool = info->section->SizeOfRawData - info->section->Misc.VirtualSize;
|
|
670
|
+
} else {
|
|
671
|
+
info->base_of_name_pool = 0;
|
|
672
|
+
info->size_of_name_pool = 0;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return 1;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
static IMAGE_SECTION_HEADER*
|
|
679
|
+
exerb_get_enclosing_section_header(const IMAGE_NT_HEADERS *nt_headers, const DWORD rva)
|
|
680
|
+
{
|
|
681
|
+
IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(nt_headers);
|
|
682
|
+
|
|
683
|
+
for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++, section++ ) {
|
|
684
|
+
if ( (rva >= section->VirtualAddress) && (rva < (section->VirtualAddress + section->Misc.VirtualSize)) ) {
|
|
685
|
+
return section;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return NULL;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
static void
|
|
693
|
+
exerb_call_initialize_function(const HMODULE handle, const char *filepath)
|
|
694
|
+
{
|
|
695
|
+
const char *filename = exerb_get_filename(filepath);
|
|
696
|
+
char funcname[128] = "Init_";
|
|
697
|
+
strncat(funcname, filename, sizeof(funcname) - strlen(funcname) - 1);
|
|
698
|
+
|
|
699
|
+
char *ext = strrchr(funcname, '.');
|
|
700
|
+
if ( ext && (stricmp(ext, ".so") == 0 || stricmp(ext, ".dll") == 0) ) {
|
|
701
|
+
*ext = '\0';
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
void (*init_proc)(void) = (void (*)(void))GetProcAddress(handle, funcname);
|
|
705
|
+
if ( !init_proc ) rb_raise(rb_eExerbRuntimeError, "Couldn't call the initialize function in the extension library. --- %s(%s)", filepath, funcname);
|
|
706
|
+
|
|
707
|
+
(*init_proc)();
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
static int
|
|
711
|
+
exerb_find_resource(const DWORD base_of_image, const int type, const int id, DWORD *base_of_item, DWORD *size_of_item)
|
|
712
|
+
{
|
|
713
|
+
const IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER*)base_of_image;
|
|
714
|
+
const IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS*)(base_of_image + dos_header->e_lfanew);
|
|
715
|
+
|
|
716
|
+
const DWORD base_of_resource = base_of_image + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
|
|
717
|
+
if ( base_of_resource == base_of_image ) return 0;
|
|
718
|
+
|
|
719
|
+
const IMAGE_RESOURCE_DIRECTORY *root_dir = (IMAGE_RESOURCE_DIRECTORY*)base_of_resource;
|
|
720
|
+
const IMAGE_RESOURCE_DIRECTORY_ENTRY *root_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root_dir + 1);
|
|
721
|
+
|
|
722
|
+
for ( WORD i = 0; i < root_dir->NumberOfNamedEntries + root_dir->NumberOfIdEntries; i++ ) {
|
|
723
|
+
if ( !root_entries[i].NameIsString && root_entries[i].Id == type ) {
|
|
724
|
+
const IMAGE_RESOURCE_DIRECTORY *type_dir = (IMAGE_RESOURCE_DIRECTORY*)(base_of_resource + root_entries[i].OffsetToDirectory);
|
|
725
|
+
const IMAGE_RESOURCE_DIRECTORY_ENTRY *type_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(type_dir + 1);
|
|
726
|
+
|
|
727
|
+
for ( WORD j = 0; j < type_dir->NumberOfNamedEntries + type_dir->NumberOfIdEntries; j++ ) {
|
|
728
|
+
if ( !type_entries[j].NameIsString && type_entries[j].Id == id ) {
|
|
729
|
+
const IMAGE_RESOURCE_DIRECTORY *item_dir = (IMAGE_RESOURCE_DIRECTORY*)(base_of_resource + type_entries[j].OffsetToDirectory);
|
|
730
|
+
const IMAGE_RESOURCE_DIRECTORY_ENTRY *item_entries = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(item_dir + 1);
|
|
731
|
+
const IMAGE_RESOURCE_DATA_ENTRY *data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(base_of_resource + item_entries[0].OffsetToData);
|
|
732
|
+
|
|
733
|
+
if ( base_of_item ) *base_of_item = base_of_image + data_entry->OffsetToData;
|
|
734
|
+
if ( size_of_item ) *size_of_item = data_entry->Size;
|
|
735
|
+
|
|
736
|
+
return 1;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return 0;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
746
|
+
static void
|
|
747
|
+
exerb_replace_import_function(const HMODULE module)
|
|
748
|
+
{
|
|
749
|
+
HMODULE kernel32 = GetModuleHandle("kernel32.dll");
|
|
750
|
+
FARPROC load_library_proc = GetProcAddress(kernel32, "LoadLibraryA");
|
|
751
|
+
FARPROC load_library_ex_proc = GetProcAddress(kernel32, "LoadLibraryExA");
|
|
752
|
+
FARPROC get_module_handle = GetProcAddress(kernel32, "GetModuleHandleA");
|
|
753
|
+
FARPROC get_proc_address_proc = GetProcAddress(kernel32, "GetProcAddress");
|
|
754
|
+
|
|
755
|
+
HMODULE self = GetModuleHandle(NULL);
|
|
756
|
+
FARPROC rb_require_proc = GetProcAddress(self, "rb_require");
|
|
757
|
+
|
|
758
|
+
#ifdef RUBY19
|
|
759
|
+
FARPROC rb_require_safe_proc = GetProcAddress(self, "rb_require_safe");
|
|
760
|
+
#endif
|
|
761
|
+
|
|
762
|
+
exerb_replace_import_function_thunk(module, load_library_proc, (FARPROC)exerb_hook_load_library);
|
|
763
|
+
exerb_replace_import_function_thunk(module, load_library_ex_proc, (FARPROC)exerb_hook_load_library_ex);
|
|
764
|
+
exerb_replace_import_function_thunk(module, get_module_handle, (FARPROC)exerb_hook_get_module_handle);
|
|
765
|
+
exerb_replace_import_function_thunk(module, get_proc_address_proc, (FARPROC)exerb_hook_get_proc_address);
|
|
766
|
+
|
|
767
|
+
// replace rb_require and rb_require_safe used by extension with ours
|
|
768
|
+
exerb_replace_import_function_thunk(module, rb_require_proc, (FARPROC)rb_require);
|
|
769
|
+
|
|
770
|
+
#ifdef RUBY19
|
|
771
|
+
exerb_replace_import_function_thunk(module, rb_require_safe_proc, (FARPROC)rb_require_safe);
|
|
772
|
+
#endif
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
static int
|
|
776
|
+
exerb_replace_import_function_thunk(const HMODULE module, const FARPROC src_proc, const FARPROC new_proc)
|
|
777
|
+
{
|
|
778
|
+
const DWORD base_of_image = (DWORD)module;
|
|
779
|
+
const IMAGE_DOS_HEADER *dos_header = (IMAGE_DOS_HEADER*)base_of_image;
|
|
780
|
+
const IMAGE_NT_HEADERS *nt_headers = (IMAGE_NT_HEADERS*)(base_of_image + dos_header->e_lfanew);
|
|
781
|
+
|
|
782
|
+
const DWORD base_of_import = base_of_image + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
783
|
+
if ( base_of_import == base_of_image ) return 0;
|
|
784
|
+
|
|
785
|
+
for ( IMAGE_IMPORT_DESCRIPTOR *desc = (IMAGE_IMPORT_DESCRIPTOR*)base_of_import; desc->Name; desc++ ) {
|
|
786
|
+
for ( DWORD *thunk = (DWORD*)(base_of_image + desc->FirstThunk); *thunk; thunk++ ) {
|
|
787
|
+
if ( *thunk == (DWORD)src_proc ) {
|
|
788
|
+
DWORD protect = 0, dummy = 0;
|
|
789
|
+
VirtualProtect(thunk, sizeof(DWORD), PAGE_READWRITE, &protect);
|
|
790
|
+
*thunk = (DWORD)new_proc;
|
|
791
|
+
VirtualProtect(thunk, sizeof(DWORD), protect, &dummy);
|
|
792
|
+
return 1;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return 0;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
static HMODULE WINAPI
|
|
801
|
+
exerb_hook_load_library(LPCTSTR filename)
|
|
802
|
+
{
|
|
803
|
+
_RPT1(_CRT_WARN, "exerb_hook_load_library('%s')\n", filename);
|
|
804
|
+
|
|
805
|
+
FILE_ENTRY_HEADER *file_entry;
|
|
806
|
+
|
|
807
|
+
if ( filename ) {
|
|
808
|
+
if ( stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
|
|
809
|
+
stricmp(filename, EXERB_LIBRUBY_SO) == 0 ) {
|
|
810
|
+
return GetModuleHandle(NULL);
|
|
811
|
+
} else if ( file_entry = exerb_find_file_entry_by_filename(filename, "dll") ) {
|
|
812
|
+
if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
|
|
813
|
+
file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
|
|
814
|
+
return exerb_preload_library(file_entry);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
return LoadLibrary(filename);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
static HMODULE WINAPI
|
|
823
|
+
exerb_hook_load_library_ex(LPCTSTR filename, HANDLE file, DWORD flags)
|
|
824
|
+
{
|
|
825
|
+
_RPT3(_CRT_WARN, "exerb_hook_load_library_ex('%s', %i, %i)\n", filename, file, flags);
|
|
826
|
+
|
|
827
|
+
FILE_ENTRY_HEADER *file_entry;
|
|
828
|
+
|
|
829
|
+
if ( filename ) {
|
|
830
|
+
if ( stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
|
|
831
|
+
stricmp(filename, EXERB_LIBRUBY_SO) == 0 ) {
|
|
832
|
+
return GetModuleHandle(NULL);
|
|
833
|
+
} else if (file_entry = exerb_find_file_entry_by_filename(filename, "dll") ) {
|
|
834
|
+
if ( file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_EXTENSION_LIBRARY ||
|
|
835
|
+
file_entry->type_of_file == FILE_ENTRY_HEADER_TYPE_DYNAMIC_LIBRARY ) {
|
|
836
|
+
return exerb_preload_library(file_entry);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return LoadLibraryEx(filename, file, flags);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
static HMODULE WINAPI
|
|
845
|
+
exerb_hook_get_module_handle(LPCTSTR filename)
|
|
846
|
+
{
|
|
847
|
+
_RPT1(_CRT_WARN, "exerb_hook_get_module_handle('%s')\n", filename);
|
|
848
|
+
|
|
849
|
+
if ( filename && (stricmp(filename, EXERB_LIBRUBY_NAME) == 0 ||
|
|
850
|
+
stricmp(filename, EXERB_LIBRUBY_SO) == 0) ) {
|
|
851
|
+
return GetModuleHandle(NULL);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
return GetModuleHandle(filename);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
static FARPROC WINAPI
|
|
858
|
+
exerb_hook_get_proc_address(HMODULE module, LPCTSTR procname)
|
|
859
|
+
{
|
|
860
|
+
_RPT2(_CRT_WARN, "exerb_hook_get_proc_address(0x%08X, '%s')\n", module, procname);
|
|
861
|
+
|
|
862
|
+
HMODULE kernel32 = GetModuleHandle("kernel32.dll");
|
|
863
|
+
|
|
864
|
+
// FIXME: �����ɂ��C���|�[�g�ɑΉ�����
|
|
865
|
+
|
|
866
|
+
if ( module == kernel32 ) {
|
|
867
|
+
if ( strcmp(procname, "LoadLibraryA") == 0 ) return (FARPROC)exerb_hook_load_library;
|
|
868
|
+
else if ( strcmp(procname, "LoadLibraryExA") == 0 ) return (FARPROC)exerb_hook_load_library_ex;
|
|
869
|
+
else if ( strcmp(procname, "GetModuleHandleA") == 0 ) return (FARPROC)exerb_hook_get_module_handle;
|
|
870
|
+
else if ( strcmp(procname, "GetProcAddress") == 0 ) return (FARPROC)exerb_hook_get_proc_address;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
return GetProcAddress(module, procname);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
////////////////////////////////////////////////////////////////////////////////
|